Ruby on rails 使用Rspec测试ActiveModel::序列化程序类

Ruby on rails 使用Rspec测试ActiveModel::序列化程序类,ruby-on-rails,ruby-on-rails-4,rspec,active-model-serializers,Ruby On Rails,Ruby On Rails 4,Rspec,Active Model Serializers,给定以下ActiveModel::Serializer类: class SampleSerializer < ActiveModel::Serializer attributes :id, :name end class SampleSerializer

给定以下
ActiveModel::Serializer
类:

class SampleSerializer < ActiveModel::Serializer
  attributes :id, :name
end
class SampleSerializer
如何使用
RSpec

假设测试这一点 这个答案假设您已经安装并配置了
rspec-rails
active\u model\u序列化程序
factory\u girl\u-rails
gems

此答案还假设您已为
示例
资源定义了一个工厂

序列化程序规范 在撰写本文时,对于的当前版本(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
    配置生成符合以下标准的json:

    subject { JSON.parse(@serialization.to_json)['data']['attributes'] }
    
使用时,只需在序列化程序上调用
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
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
class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end
# frozen_string_literal: true

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

@gnerkus的回答有助于指导我自己的实现,但我选择了另一种方法。测试
ActiveModel::Serializer
的返回值(序列化程序未执行任何附加处理)似乎是在测试特定键的存在以及
ActiveModel::Serializer
是否工作。为了避免测试
ActiveModel::Serializer
,而是测试特定键是否存在,下面是我测试给定序列化程序的方法:

it 'should include a correct name' do
  sample = FactoryBot.create(:sample)
  serializer = SampleSerializer.new(sample)
  expect(serializer.serializable_hash[:name]).to eq 'Heisenberg'
end
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
class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end
# frozen_string_literal: true

class UserSerializer < ApplicationSerializer
  attributes :first_name, :last_name, :verification, :avatar_url, :state, :payin_ability
end
请注意使用
contain_justice
:这可以确保除了您指定的键之外,没有其他键存在。如果包含意外属性,使用
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

你可以用这种现代风格写作

类别序列化程序:

it 'should include a correct name' do
  sample = FactoryBot.create(:sample)
  serializer = SampleSerializer.new(sample)
  expect(serializer.serializable_hash[:name]).to eq 'Heisenberg'
end
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
class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end
# frozen_string_literal: true

class UserSerializer < ApplicationSerializer
  attributes :first_name, :last_name, :verification, :avatar_url, :state, :payin_ability
end
你可以用
subject{descripted_class.new(user).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
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
class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end
# frozen_string_literal: true

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

这是最棒的。不知道你能不能帮我解释一下。我有一个多态序列化程序,在过去的几个小时里,我无法使用上面概述的步骤获取要呈现的相关记录。如果我直接使用SomeSerializer.new(resource.associations),我似乎能够看到它们,但这绝不是一个序列化的数据包。感谢注意:ActiveModel::Serializer::Adapter.create已弃用。使用ActiveModelSerializers::Adapter.create.in我应该在什么文件中编写测试这太棒了,而且工作得非常好。谢谢@luke的回答。@luke你能看看我的问题吗?这个解决方案是我见过的最好的解决方案NHI@Tanbir Hasan你能看看我在0.10.10版中的问题吗?当前用户可以在序列化程序中找到。要使它在测试中工作,您需要添加
let(:serializer){descripted_class.new(category,scope:user,scope_name::current_user)}
只需清除解决方案,但它不注意根节点(type)