2014-02-28 6 views
7

Ich verwende aktive Modell-Serializer, um JSON-Antworten von einem Rails-Controller zu rendern.Active Model Serializer, testet, welcher Serializer zum Rendern der Antwort verwendet wird

Ich habe eine Controller-Aktion wie folgt aus:

def show 
    @foo = Foo.find(params[:id]) 
    if @foo.user == current_user 
    render json: @foo, serializer: FooSerializer 
    else 
    render json: @foo, serializer: TrimmedFooSerializer 
    end 
end 

Ich möchte testen können, welche Serializer in meinem Rspec Controller Tests verwendet wurde. Ist es möglich, einen Verweis auf den Serialisierer aus den Tests zu erhalten?

UPDATE:

Ich glaube nicht, dass dies eine korrekte Verwendung des Serializer. Ich habe jetzt Logik im Serialisierer selbst, um Attribute bedingt einzuschließen. Der Controller sollte sich nicht wirklich darum kümmern, welcher Serializer verwendet werden soll.

Antwort

3

Sie können dies versuchen. Ich gehe davon aus, dass Sie factory_girl verwenden. Sie können einen anderen Benutzer durch Rücksendung für current_user

describe "show" do 
    it "should use FooSerializer to serialize if the logged in user is the same as params user" do 
    user = FactoryGirl.create(:user) 
    controller.stub(:current_user).and_return(user) 
    FooSerializer.any_instance.should_receive(:to_json).and_return("{\"key\": \"value\"") 
    get :show, :id => user.id 
    response.should be_success 
    end 
end 
14

den anderen Test schreiben Es hat eine Weile gewesen, da jemand antwortete aber im Falle Zukunft Googler diese finden, wie ich den folgenden Ansatz:

RSpec::Matchers.define :serialize_object do |object| 
    match do |response| 
    @serializer_klass.new(object).to_json == response.body 
    end 

    chain :with do |serializer_klass| 
    @serializer_klass = serializer_klass 
    end 
end 

Dann in Ihren Tests können Sie tun:

expect(response).to serialize_object(claim).with(ClaimSerializer) 

Bitte beachte, dass ich nicht der Matcher ‚serialize‘ nannte, weil shoulda bereits eine Matcher dieses Namens definiert.

+0

sehr elegant ein nützlicher Ansatz – Calin

1

Zu erarbeiten weiter Dan Draper's Antwort, fand ich, dass, wenn der JsonApi-Adapter, ist dies der Weg zu gehen ist:

RSpec::Matchers.define :serialize_resource do |object| 
    match do |response| 
    serialized_json(object) == response.body 
    end 

    chain :with do |serializer_klass| 
    @serializer_klass = serializer_klass 
    end 

    failure_message do |response| 
    "expected response body #{serialized_json(object)}, got #{response.body}" 
    end 

    def serialized_json(object) 
    serializer = @serializer_klass.new(object) 
    adapted = ActiveModelSerializers::Adapter::JsonApi.new(serializer) 
    adapted.serializable_hash.to_json 
    end 
end 
1

ich, was Knightstick oben und es ein wenig verbessert haben nahm, wie zum Beispiel , die Fehlermeldung und durch Hinzufügen der Fähigkeit, sowohl einzelne Ressourcen oder eine Ressourcensammlung zu behandeln (ich benutze das Juwel "active_model_serializers", Version 0.10.0).

RSpec::Matchers.define :serialize_resource do |resource| 
    match do |response| 
    serialized_json(resource) == response.body 
    end 

    chain :with do |serializer_klass| 
    @serializer_klass = serializer_klass 
    end 

    failure_message do |response| 
    "expected response body #{serialized_json(resource).inspect}, got #{response.body.inspect}" 
    end 

    def serialized_json(resource) 
    options = if resource.is_a?(Array) 
       { each_serializer: @serializer_klass } 
       else 
       { serializer: @serializer_klass } 
       end 

    serializable = ActiveModelSerializers::SerializableResource.new(resource, options) 
    serializable.serializable_hash.to_json 
    end 
end