2013-07-06 15 views
14

Napisałem kilka Rack-Middleware, a teraz próbuję przetestować je za pomocą Rspec. Ale wszystkie Rack-Middleware są tworzone z argumentem "app", który reprezentuje samą aplikację Rails. Jak wyśmiewacie się z tego w Rspec?Testowanie oprogramowania pośredniego z Rspec

Na przykład

describe MyMiddleWare do 
    let(:app) { # How do I mock a Rails app object here? } 
    subject { MyMiddleWare.new(app: app) } 

    it 'should blah blah blah' do 
     # a bunch of tests go here 
    end 
end 

Odpowiedz

18

You wystarczy najprostsza na świecie aplikacja Rack:

let(:app) { lambda {|env| [200, {'Content-Type' => 'text/plain'}, ['OK']]} } 

Ponadto Twój konstruktor oprogramowania pośredniego powinien otrzymać aplikację jako pierwszą ter nie hash tak powinien brzmieć:

subject { MyMiddleWare.new(app) } 

według wszelkiego prawdopodobieństwa, choć nasz test będzie musiał ustalić, jaki wpływ wywarło na middleware wniosku. Możesz więc napisać nieco bardziej wyrafinowaną aplikację do obsługi stojaków, aby śledzić oprogramowanie pośredniczące.

class MockRackApp 

    attr_reader :request_body 

    def initialize 
    @request_headers = {} 
    end 

    def call(env) 
    @env = env 
    @request_body = env['rack.input'].read 
    [200, {'Content-Type' => 'text/plain'}, ['OK']] 
    end 

    def [](key) 
    @env[key] 
    end 

end 

, a następnie prawdopodobnie będziesz chciał użyć Rack :: MockRequest do wysłania żądania. Coś w rodzaju:

describe MyMiddleWare do 

    let(:app) { MockRackApp.new } 
    subject { described_class.new(app) } 

    context "when called with a POST request" do 
    let(:request) { Rack::MockRequest.new(subject) } 
    before(:each) do 
     request.post("/some/path", input: post_data, 'CONTENT_TYPE' => 'text/plain') 
    end 

    context "with some particular data" do 
     let(:post_data) { "String or IO post data" } 

     it "passes the request through unchanged" do 
     expect(app['CONTENT_TYPE']).to eq('text/plain') 
     expect(app['CONTENT_LENGTH'].to_i).to eq(post_data.length) 
     expect(app.request_body).to eq(post_data) 
     end 
    end 
    end 
end 
+0

Nie ma tutaj tematu, jak to działa? – Calin

+0

To w rzeczywistości nie jest prawidłową aplikacją Rack. "Lambda" musiałaby przyjąć argument, by być prawidłową aplikacją Rack. – branch14

+0

Zaktualizowano, aby opublikować post - dzięki, @Calin. – Ritchie

0

wierzę, należy użyć żądania specyfikacje symulujące żądania HTTP (Twój middleware powinny być zawarte w szynach middleware stosie). Zobacz więcej informacji na temat specyfikacji zamówień rspec here.

UPD Chyba znalazłem dokładnie to, co trzeba, do Test :: Unit, ale łatwo przerobić na RSpec: rack-ssl-enforcer

0

Testowałem kopalni jak tak

describe Support::CharConverter do 

    let(:env_hash) do 
    { 
     "HTTP_REFERER" => "", 
     "PATH_INFO" => "foo", 
     "QUERY_STRING" => "bar", 
     "REQUEST_PATH" => "is", 
     "REQUEST_URI" => "here", 
    } 
    end 

    subject do 
    Support::CharConverter.new(env_hash) 
    end 

    context 'sanitize_env' do 

    it 'should keep key values the same if nothing to sanitize' do 
     sanitized_hash = subject.sanitize_env(env_hash) 
     # k = env_hash.keys[5] 
     # v = env_hash.values[5] 
     env_hash.each do |k, v| 
     sanitized_hash[k].encoding.name.should eq("US-ASCII") 
     sanitized_hash[k].should eq(v) 
     sanitized_hash[k].valid_encoding?.should eq(true) 
     end 
    end 
    end 
end