Test ActiveModel::Serializer classes with Rspec

前端 未结 4 1936
故里飘歌
故里飘歌 2020-12-24 11:45

Given the following ActiveModel::Serializer class:

class SampleSerializer < ActiveModel::Serializer
  attributes :id, :name
end
4条回答
  •  梦谈多话
    2020-12-24 12:23

    @gnerkus’s answer helped to guide my own implementation, but I chose a different approach. Testing the returned values of ActiveModel::Serializer where no additional processing is being done by the Serializer seems to be testing both the presence of particular keys and whether ActiveModel::Serializer is working. To avoid testing ActiveModel::Serializer and instead test whether specific keys are present, here’s how I would test a given Serializer:

    describe SampleSerializer do
      subject {  SampleSerializer.new(sample) }
    
      it "includes the expected attributes" do
        expect(subject.attributes.keys).
          to contain_exactly(
            :sample_key,
            :another_sample_key
          )
      end
    
      def sample
        @sample ||= build(:sample)
      end
    end
    

    Notice the use of contain_exactly: this ensures that no other keys than the ones you specify are present. Using include would result in tests not failing if unexpected attributes are included. This scales nicely when you update the attributes but fail to update your tests, as the test will throw an error and force you to keep everything up to date.

    The exception to testing keys only would be when you want to test custom methods you’ve added to a given serializer, in which case I would highly recommend writing a test for the returned value/s impacted by that method.

    Update

    For testing relationships, you'll need to do a little more setup with the serializer. I avoid this setup for simple serializers, but this modified setup will help you test the presence of links, relationships, etc.

    describe SampleSerializer do
      subject do
        ActiveModelSerializers::Adapter.create(sample_serializer)
      end
    
      it "includes the expected attributes" do
        expect(subject_json(subject)["data"]["attributes"].keys).
          to contain_exactly(
            "date"
          )
      end
    
      it "includes the related Resources" do
        expect(subject_json(subject)["data"]["relationships"].keys).
          to contain_exactly(
            "other-resources"
          )
      end
    
      def subject_json(subject)
        JSON.parse(subject.to_json)
      end
    
      def sample_resource
        @sample_resource ||= build(:sample_resource)
      end
    
      def sample_serializer
        @sample_serializer ||=
          SampleSerializer.new(sample_resource)
      end
    end
    

提交回复
热议问题