RSpec 序列化器测试的相等匹配器失败
RSpec equality matcher failing for serializer test
我正在为我的一个活动模型序列化程序编写测试,以确保 JSON 输出符合我的预期。但是,我无法弄清楚为什么 RSpec 正在解析我的 'expected' 输出以遗漏我的测试作业数组,我不明白为什么我无法获得 'expected' 和 'got' 输出彼此平等。有一次,我什至将 'got' 结果复制粘贴到我的 'expected' 输入,但仍然收到一条失败消息,指出两个字符串不相等。但是,当我使用 == 在 REPL 中比较这两个字符串时,输出是 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
看起来你的 testjobs
不匹配
completed_at\":nu...r\"}}],\"branch\"
对比
completed_at\":nu...s\":[],
您应该设置规格,以便 testjobs
也返回。
请注意,diff 字符串在中间 cut
- 这是 eq 匹配器与字符串一起使用时最烦人的部分之一。
编辑:您可能不会切换到比较 arrays/hashes 而不是字符串以获得更好的差异。 expect(serializer).to eq {testrun: "..."}
(在你的断言中删除 to_json
)
工作解决方案:
我添加了行
serializer.testjobs << testjob
显式地将测试作业与对象相关联,测试现在通过了。
您的测试未通过的原因很简单:在 it
块内,您在创建 Testjob
记录时分配了 Testrun id (1)
,但是 Testrun
记录不存在。
SomeActiveRecord.new()
在您调用 save()
之前不会创建任何实际记录,或者您可以为此调用 SomeActiveRecord.create
。
some_active_record = SomeActiveRecord.new(...)
some_active_record.save
# or
some_active_record = SomeActiveRecord.create(...)
所以最终的解决方案可能类似于:
it "creates special JSON for the API" do
testrun = Testrun.create(id: 1, name: "name", run_at: nil, state: "pending", branch_id: branch.id)
serializer = TestrunSerializer.new(testrun)
testjob = Testjob.create(id: 8, active: false, testchunk_id: testchunk.id, testrun_id: testrun.id)
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
改进范围:
请查看 active_model_serializers
存储库中 :json
适配器的测试:https://github.com/rails-api/active_model_serializers/blob/v0.10.6/test/action_controller/json/include_test.rb。
您可以使用 rspec
轻松地将测试转换为套件。
如果你想测试 json 输出,那么你应该把测试放在 controller
或 request
规范下;而不是在序列化程序中。因为渲染 json 是适配器的责任;序列化程序仅向适配器提供其中定义的所有属性和关联。
我正在为我的一个活动模型序列化程序编写测试,以确保 JSON 输出符合我的预期。但是,我无法弄清楚为什么 RSpec 正在解析我的 'expected' 输出以遗漏我的测试作业数组,我不明白为什么我无法获得 'expected' 和 'got' 输出彼此平等。有一次,我什至将 'got' 结果复制粘贴到我的 'expected' 输入,但仍然收到一条失败消息,指出两个字符串不相等。但是,当我使用 == 在 REPL 中比较这两个字符串时,输出是 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
看起来你的 testjobs
不匹配
completed_at\":nu...r\"}}],\"branch\"
对比
completed_at\":nu...s\":[],
您应该设置规格,以便 testjobs
也返回。
请注意,diff 字符串在中间 cut
- 这是 eq 匹配器与字符串一起使用时最烦人的部分之一。
编辑:您可能不会切换到比较 arrays/hashes 而不是字符串以获得更好的差异。 expect(serializer).to eq {testrun: "..."}
(在你的断言中删除 to_json
)
工作解决方案:
我添加了行
serializer.testjobs << testjob
显式地将测试作业与对象相关联,测试现在通过了。
您的测试未通过的原因很简单:在 it
块内,您在创建 Testjob
记录时分配了 Testrun id (1)
,但是 Testrun
记录不存在。
SomeActiveRecord.new()
在您调用 save()
之前不会创建任何实际记录,或者您可以为此调用 SomeActiveRecord.create
。
some_active_record = SomeActiveRecord.new(...)
some_active_record.save
# or
some_active_record = SomeActiveRecord.create(...)
所以最终的解决方案可能类似于:
it "creates special JSON for the API" do
testrun = Testrun.create(id: 1, name: "name", run_at: nil, state: "pending", branch_id: branch.id)
serializer = TestrunSerializer.new(testrun)
testjob = Testjob.create(id: 8, active: false, testchunk_id: testchunk.id, testrun_id: testrun.id)
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
改进范围:
请查看 active_model_serializers
存储库中 :json
适配器的测试:https://github.com/rails-api/active_model_serializers/blob/v0.10.6/test/action_controller/json/include_test.rb。
您可以使用 rspec
轻松地将测试转换为套件。
如果你想测试 json 输出,那么你应该把测试放在 controller
或 request
规范下;而不是在序列化程序中。因为渲染 json 是适配器的责任;序列化程序仅向适配器提供其中定义的所有属性和关联。