我有一个最小的规格:
it "fetches a list of all databases" do get "/v1/databases" json = JSON.parse(response.body) json.length.must_equal Database.count json.map{|d| d["id"]}.must_equal Database.all.pluck(:id) end
但是,这失败了:
Expected: [610897332, 251689721] Actual: [251689721, 610897332]
我可以同时订购它们,但这会增加混乱:
json.map{|d| d["id"]}.sort.must_equal Database.all.pluck(:id).sort
事实上,它map{}
已经与测试有点无关并且增加了混乱,我宁愿不再添加更多.
是否有断言或助手来测试是否所有物品enumerator1
都在enumerator2
?
MiniTest Rails Shoulda具有一个assert_same_elements
断言,该断言:
断言两个数组包含相同的元素,相同的次数。本质上==,但无序。
assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes
TL; DR检查这个问题的最直接方法是在检查数组之前对数组进行排序.
json.map{|d| d["id"]}.sort.must_equal Database.all.pluck(:id).sort
还在?好的.我们来谈谈比较数组中的元素.
事实上,地图{}已经与测试有点无关并且增加了混乱,我宁愿不再添加更多.
嗯,这是问题的一部分.您的JSON包含一个JSON对象数组,而调用Database.pluck
将返回其他内容,可能是整数.您需要将JSON对象和查询转换为相同的数据类型.所以说这.map{}
是无关紧要是不准确的,如果它感觉像是混乱,那就是因为你在断言中做了很多事情.尝试拆分该行代码并使用意图揭示名称:
sorted_json_ids = json.map{|d| d["id"]}.sort sorted_db_ids = Database.order(:id).pluck(:id) sorted_json_ids.must_equal sorted_db_ids
在测试中有更多的代码行,但更好地传达了意图.然而,我听到你的话语"无关紧要"和"混乱"在我脑海中回荡.我打赌你不喜欢这个解决方案."它的工作太多了!" 并且"为什么我必须对此负责?" 好吧好吧.我们有更多选择.更智能的断言怎么样?
RSpec有一个很好的小匹配器match_array
,可以满足您的需求.它对数组进行排序和比较,如果它们不匹配则打印出一条好消息.我们可以做类似的事情.
def assert_matched_arrays expected, actual assert_equal expected.to_ary.sort, actual.to_ary.sort end it "fetches a list of all databases" do get "/v1/databases" json = JSON.parse(response.body) assert_matched_arrays Database.pluck(:id), json.map{|d| d["id"]} end
"但这是一个断言而不是期望!" 是的,我知道.放松.您可以通过调用将断言转换为期望infect_an_assertion
.但要做到这一点,您可能希望添加断言方法,以便可以在每个Minitest测试中使用它.所以在我的test_helper.rb
文件中我添加以下内容:
module MiniTest::Assertions ## # Fails unless <tt>exp</tt> and <tt>act</tt> are both arrays and # contain the same elements. # # assert_matched_arrays [3,2,1], [1,2,3] def assert_matched_arrays exp, act exp_ary = exp.to_ary assert_kind_of Array, exp_ary act_ary = act.to_ary assert_kind_of Array, act_ary assert_equal exp_ary.sort, act_ary.sort end end module MiniTest::Expectations ## # See MiniTest::Assertions#assert_matched_arrays # # [1,2,3].must_match_array [3,2,1] # # :method: must_match_array infect_an_assertion :assert_matched_arrays, :must_match_array end
现在您的断言可用于任何测试,您的期望将在每个对象上可用.
it "fetches a list of all databases" do get "/v1/databases" json = JSON.parse(response.body) json.map{|d| d["id"]}.must_match_array Database.pluck(:id) end