使用Rspec测试ActiveModel :: Serializer类

时间:2016-02-13 03:33:16

标签: ruby-on-rails ruby-on-rails-4 rspec active-model-serializers

给出以下ActiveModel::Serializer类:

class SampleSerializer < ActiveModel::Serializer
      attributes :id, :name
end

如何使用RSpec测试?

5 个答案:

答案 0 :(得分:25)

假设

此答案假设您已安装并配置了rspec-railsactive_model_serializersfactory_girl_rails宝石。

此答案还假设您已为Sample资源定义了工厂。

Serializer规范

对于编写本文时active_model_serializers的当前版本(0.10.0.rc3),ActiveModel::Serializer类不接收to_json,而是包含在适配器类中。要获取包装在序列化程序实例中的模型的序列化,必须创建适配器的实例:

before(:each) do
  # Create an instance of the model
  @sample = FactoryGirl.build(:sample)

  # Create a serializer instance
  @serializer = SampleSerializer.new(@sample)

  # Create a serialization based on the configured adapter
  @serialization = ActiveModelSerializers::Adapter.create(@serializer)
end

适配器实例接收to_json方法并返回模型的序列化。

subject { JSON.parse(@serialization.to_json) }

然后可以在返回的JSON上运行期望。

it 'should have a name that matches' do
  expect(subject['name']).to eql(@sample.name)
end

解析JSON响应时,必须考虑适配器配置:

  • 默认配置:attributes生成没有根密钥的JSON响应:

    subject { JSON.parse(@serialization.to_json) }
    
  • :json配置根据模型名称生成带有根密钥的JSON响应:

    subject { JSON.parse(@serialization.to_json)['sample'] }
    
  • :json_api配置生成符合jsonapi标准的JSON:

    subject { JSON.parse(@serialization.to_json)['data']['attributes'] }
    

答案 1 :(得分:16)

使用active_model_serializers时,只需在序列化程序上调用serializable_hash即可轻松实现:

it 'should include a correct name' do
  sample = FactoryBot.create(:sample)
  serializer = SampleSerializer.new(sample)
  expect(serializer.serializable_hash[:name]).to eq 'Heisenberg'
end

答案 2 :(得分:14)

@ gnerkus的回答有助于指导我自己的实施,但我选择了不同的方法。测试ActiveModel::Serializer的返回值,其中串行器没有进行额外的处理,似乎正在测试特定键的存在以及ActiveModel::Serializer是否正常工作。为避免测试ActiveModel::Serializer而是测试是否存在特定键,以下是测试给定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

请注意contain_exactly的使用:这可确保不存在除指定键之外的其他键。如果包含意外属性,使用include将导致测试失败。当您更新属性但未能更新测试时,这会很好地扩展,因为测试会抛出错误并迫使您保持最新状态。

测试密钥的例外仅在于您要测试已添加到给定序列化程序的自定义方法时,在这种情况下,我强烈建议为受该方法影响的返回值编写测试。

更新

为了测试关系,您需要使用序列化程序进行更多设置。我为简单的序列化程序避免了这种设置,但是这个修改后的设置将帮助您测试链接,关系等的存在。

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

答案 3 :(得分:5)

示例:您可以编写这种现代风格。

类别序列化器:

class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end

RSpec的:

require 'rails_helper'

RSpec.describe CategorySerializer, type: :serializer do
  let(:category) { FactoryGirl.build(:category) }
  let(:serializer) { described_class.new(category) }
  let(:serialization) { ActiveModelSerializers::Adapter.create(serializer) }

  let(:subject) { JSON.parse(serialization.to_json) }

  it 'has an id that matches' do
    expect(subject['id']).to eql(category.id)
  end

  it 'has a name that matches' do
    expect(subject['name']).to eql(category.name)
  end  
end

答案 4 :(得分:1)

你可以使用 subject { described_class.new(user).serializable_hash } 创建序列化对象。 我下面的例子

用户序列化器:

# frozen_string_literal: true

class UserSerializer < ApplicationSerializer
  attributes :first_name, :last_name, :verification, :avatar_url, :state, :payin_ability
end

Rspec

# frozen_string_literal: true

RSpec.describe UserSerializer, type: :serializer do
  let(:user) { create(:user) }

  describe '.serializable_hash' do
    subject { described_class.new(user).serializable_hash }

    it { expect(subject).to include(:first_name, :last_name, :verification, :avatar_url, :state, :payin_ability) }

    it 'returns correct keys and values' do
      expect(subject).to include(
        first_name: be_a(String),
        last_name: be_a(String),
        verification: be_a(String),
        avatar_url: (be_a(String).or be_nil),
        state: be_kind_of(String),
        payin_ability: (be(true).or be(false)),
      )
    end
  end
end