Given the following ActiveModel::Serializer class:
class SampleSerializer < ActiveModel::Serializer
  attributes :id, :name
end
How can this be tested with RSpec?
Given the following ActiveModel::Serializer class:
class SampleSerializer < ActiveModel::Serializer
  attributes :id, :name
end
How can this be tested with RSpec?
This answer assumes you have the rspec-rails, active_model_serializers and factory_girl_rails gems installed and configured.
This answer also assumes you have defined a factory for the Sample resource.
For the current version(0.10.0.rc3) of active_model_serializers at the time of writing, ActiveModel::Serializer classes do not receive to_json and are , instead, wrapped in an adapter class. To obtain the serialization of a model wrapped in a serializer instance, an instance of an adapter must be created:
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
The adapter instance receives the to_json method and returns the serialization of the model. 
subject { JSON.parse(@serialization.to_json) }
Expectations can then be run on the JSON returned.
it 'should have a name that matches' do
  expect(subject['name']).to eql(@sample.name)
end
When parsing the JSON response, the adapter configuration must be taken into consideration:
The default config, :attributes, generates a JSON response without a root key:
subject { JSON.parse(@serialization.to_json) }
The :json config generates a JSON response with a root key based on the model's name:
subject { JSON.parse(@serialization.to_json)['sample'] }
The :json_api config generates a JSON that conforms to the jsonapi standard:
subject { JSON.parse(@serialization.to_json)['data']['attributes'] }
 
    
     
    
    When using active_model_serializers, there is a much easier way by simply calling serializable_hash on the 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
 
    
    @gnerkus’s answer helped to guide my own implementation, but I chose a different approach. Testing the returned values of ActiveModel::Serializer where no additional processing is being done by the Serializer seems to be testing both the presence of particular keys and whether ActiveModel::Serializer is working. To avoid testing ActiveModel::Serializer and instead test whether specific keys are present, here’s how I would test a given 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
Notice the use of contain_exactly: this ensures that no other keys than the ones you specify are present. Using include would result in tests not failing if unexpected attributes are included. This scales nicely when you update the attributes but fail to update your tests, as the test will throw an error and force you to keep everything up to date.
The exception to testing keys only would be when you want to test custom methods you’ve added to a given serializer, in which case I would highly recommend writing a test for the returned value/s impacted by that method.
For testing relationships, you'll need to do a little more setup with the serializer. I avoid this setup for simple serializers, but this modified setup will help you test the presence of links, relationships, etc.
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
 
    
     
    
    Example: You can writing this modern style.
Category serializer:
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
 
    
    You can just use
subject { described_class.new(user).serializable_hash } to create serialized object.
My example below
UserSerializer:
# frozen_string_literal: true
class UserSerializer < ApplicationSerializer
  attributes :first_name, :last_name, :verification, :avatar_url, :state, :payin_ability
end
Rspec
# frozen_string_literal: true
RSpec.describe UserSerializer, type: :serializer do
  let(:user) { create(:user) }
  describe '.serializable_hash' do
    subject { described_class.new(user).serializable_hash }
    it { expect(subject).to include(:first_name, :last_name, :verification, :avatar_url, :state, :payin_ability) }
    it 'returns correct keys and values' do
      expect(subject).to include(
        first_name: be_a(String),
        last_name: be_a(String),
        verification: be_a(String),
        avatar_url: (be_a(String).or be_nil),
        state: be_kind_of(String),
        payin_ability: (be(true).or be(false)),
      )
    end
  end
end
