ruby on rails - Тестирование классов ActiveModel:: Serializer с помощью Rspec




ruby-on-rails ruby-on-rails-4 (3)

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

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

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

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

Для текущей версии (0.10.0.rc3) active_model_serializers на момент написания, классы 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'] }

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

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

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


Ответ @ gnerkus помог мне в реализации, но я выбрал другой подход. Проверка возвращаемых значений ActiveModel::Serializer когда 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

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

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

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






active-model-serializers