web-dev-qa-db-ja.com

ActiveModel :: SerializerクラスをRspecでテストする

次のActiveModel::Serializerクラス:

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

RSpecでこれをどのようにテストできますか?

30
gnerkus

仮定

この回答では、rspec-Railsactive_model_serializersおよびfactory_girl_Rails gemsがインストールおよび構成されています。

この回答は、Sampleリソースのファクトリを定義していることも前提としています。

シリアライザーの仕様

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 configは、モデルの名前に基づいてルートキーを持つJSON応答を生成します。

    subject { JSON.parse(@serialization.to_json)['sample'] }
    
  • :json_api configは、 jsonapi 標準に準拠するJSONを生成します。

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

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
18
Jan Klimo

@gnerkusの答えは、私自身の実装をガイドするのに役立ちましたが、別のアプローチを選択しました。シリアライザーによって追加処理が行われていないActiveModel::Serializerの戻り値のテストは、特定のキーの存在とActiveModel::Serializerが機能しているかどうかの両方をテストしているようです。 ActiveModel::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
15
Luke Keller

例:このモダンなスタイルを書くことができます。

カテゴリシリアライザー:

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
6