Подтвердить что ты не робот

Test ActiveModel:: Сериализаторы классов с Rspec

Учитывая следующий класс ActiveModel::Serializer:

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

Как это можно проверить с помощью RSpec?

4b9b3361

Ответ 1

Предположения

В этом ответе предполагается, что у вас установлены и настроены rspec-rails, active_model_serializers и factory_girl_rails.

Этот ответ также предполагает, что вы определили фабрику для ресурса Sample.

Спецификация сериализатора

Для текущей версии (0.10.0.rc3) active_model_serializer на момент написания классы to_json 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, который соответствует стандарту jsonapi:

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

Ответ 2

При использовании active_model_serializer существует гораздо более простой способ, просто вызывая 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

Ответ 3

Ответ на

@gnerkuss помог мне вести собственную реализацию, но я выбрал другой подход. Тестирование возвращаемых значений 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 приведет к тому, что тесты не сбой, если включены неожиданные атрибуты. Это хорошо масштабируется, когда вы обновляете атрибуты, но не обновляете свои тесты, поскольку тест выдает ошибку и заставляет вас следить за обновлениями.

Исключением для проверки ключей будет только то, когда вы хотите протестировать пользовательские методы, которые вы добавили в данный сериализатор, и в этом случае я настоятельно рекомендую написать тест для возвращаемого значения /s, воздействующего на этот метод.

Update

Для тестирования отношений вам потребуется немного настроить с помощью сериализатора. Я избегаю этой настройки для простых сериализаторов, но эта измененная настройка поможет вам проверить наличие ссылок, отношений и т.д.

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

Ответ 4

Пример: вы можете написать этот современный стиль.

Сериализатор категории:

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