Учитывая следующий класс ActiveModel::Serializer
:
class SampleSerializer < ActiveModel::Serializer
attributes :id, :name
end
Как это можно проверить с помощью RSpec
?
Учитывая следующий класс ActiveModel::Serializer
:
class SampleSerializer < ActiveModel::Serializer
attributes :id, :name
end
Как это можно проверить с помощью RSpec
?
В этом ответе предполагается, что у вас установлены и настроены 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'] }
При использовании 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
@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, воздействующего на этот метод.
Для тестирования отношений вам потребуется немного настроить с помощью сериализатора. Я избегаю этой настройки для простых сериализаторов, но эта измененная настройка поможет вам проверить наличие ссылок, отношений и т.д.
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