Techioz Blog

RSpec 等価マッチャーがシリアライザー テストで失敗する

概要

JSON 出力が期待どおりであることを確認するために、アクティブ モデル シリアライザーの 1 つに対するテストを作成しています。しかし、RSpec がテストジョブの配列を除外するために私の ‘expected’ 出力を解析する理由がわかりません。また、なぜ ‘expected’ と ‘got’ の出力を互いに等しくできないのかもわかりません。ある時点で、「得られた」結果を「期待された」入力にコピー&ペーストしましたが、それでも 2 つの文字列が等しくないという失敗メッセージを受け取りました。ただし、REPL で == を使用してこれら 2 つの文字列を比較すると、出力は true でした。効果的なテストを行うには、これらの問題をどのように解決すればよいでしょうか?

RSpec Error:

Failures:

  1) TestrunSerializer creates special JSON for the API
     Failure/Error: expect(serializer.to_json).to eq('{"testrun":{"id":1,"run_at":null,"started_at":null,"state":"pending","completed_at":null,"testjobs":[{"id":2,"active":false,"testchunk_id":2,"testrun_id":1,"testchunk_name":"flair","testchunk":{"id":15,"name":"flair"}}],"branch":{"id":1,"name":"dev","repository":{"id":321,"url":"fakeurl.com"}}}}')

       expected: "{\"testrun\":{\"id\":1,\"run_at\":null,\"started_at\":null,\"state\":\"pending\",\"completed_at\":nu...r\"}}],\"branch\":{\"id\":1,\"name\":\"dev\",\"repository\":{\"id\":321,\"url\":\"fakeurl.com\"}}}}"
            got: "{\"testrun\":{\"id\":1,\"run_at\":null,\"started_at\":null,\"state\":\"pending\",\"completed_at\":nu...s\":[],\"branch\":{\"id\":1,\"name\":\"dev\",\"repository\":{\"id\":321,\"url\":\"fakeurl.com\"}}}}"

       (compared using ==)
     # ./spec/serializers/testrun_spec.rb:11:in `block (2 levels) in <top (required)>'

Finished in 0.79448 seconds (files took 5.63 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/serializers/testrun_spec.rb:8 # TestrunSerializer creates special JSON for the API

RSpec テストは次のとおりです。

require 'rails_helper'

describe TestrunSerializer, type: :serializer do
  let(:repo)      { Repository.create(id: 321, url: "fakeurl.com") }
  let(:branch)    { Branch.create(id: 1,name: "dev", repository_id: repo.id) }
  let(:testchunk) { Testchunk.create(id: 15, name: "flair") }

  it "creates special JSON for the API" do
    serializer = TestrunSerializer.new Testrun.new("id":1, name: "name", "run_at": nil, state: "pending", branch_id: branch.id)
    testjob = Testjob.create(id: 8, active: false, testchunk_id: testchunk.id, testrun_id: 1)
    expect(serializer.to_json).to eq('{"testrun":{"id":1,"run_at":null,"started_at":null,"state":"pending","completed_at":null,"testjobs":[{"id":2,"active":false,"testchunk_id":2,"testrun_id":1,"testchunk_name":"flair","testchunk":{"id":15,"name":"flair"}}],"branch":{"id":1,"name":"dev","repository":{"id":321,"url":"fakeurl.com"}}}}')
  end
end

実際のシリアライザーは次のとおりです。

class TestrunSerializer < ActiveModel::Serializer
  attributes :id, :run_at, :started_at, :state, :completed_at, :testjobs
  has_many :testjobs
  has_one :branch
end 

使用されているテクノロジー: Rails 5.1、RSpec 3.6、Ruby 2.4

解決策

テストジョブが一致していないようです

completed_at\":nu...r\"}}],\"branch\"

completed_at\":nu...s\":[],

テストジョブも返されるように仕様を設定する必要があります。

diff 文字列が途中で切れていることに注意してください。これは、文字列で使用する場合、eq matcher で最も厄介な部分の 1 つです。

編集:より良い差分を取得するために、文字列の代わりに配列/ハッシュの比較に切り替えることもできます。 Expect(serializer).to eq {testrun: “…”} (アサーションに to_json をドロップ)