提问人:23tux 提问时间:9/1/2023 最后编辑:mechnicov23tux 更新时间:9/1/2023 访问量:78
使用 RSpec 测试嵌套哈希时随机排序数组的匹配
Matching of randomly ordered array when test nested hash with RSpec
问:
在我的 RSpec 测试中,我经常遇到像这样比较深度嵌套哈希的挑战
{ foo: ["test", { bar: [1,2,3] }] }
这些值是从无法保证顺序的数据库中读取的,我也不关心顺序。因此,当我在测试中比较两个哈希值时,我总是必须确保双方都强制执行顺序:[1,2,3]
# my_class.rb
class MyClass
def self.data
read_db.sort
end
end
expected_data = { foo: ["test", { bar: [1,2,3].sort }] }
expect(MyClass.data).to eq(expected_data)
我真的很不喜欢这样一个事实,即我必须更改我的生产代码只是因为我的测试环境。
当然,我可以停止比较整个哈希值并专注于单个键,因此可以删除生产代码中的自定义排序:
actual_data = MyClass.data
expect(actual_data.fetch(:foo)[0]).to eq("test")
expect(actual_data.fetch(:foo)[1].fetch(:bar)).to match_array([1,2,3])
但这使得整个规范非常复杂且难以阅读。
因此,我考虑创建一个自定义的“无序数组”类 Bag
,当它进行比较时,它会忽略顺序:
class Bag < Array
def eql?(other)
sort_by(&:hash) == other.sort_by(&:hash)
end
alias == eql?
end
但这只有在类位于比较的左侧时才有效:Bag
expect(Bag.new([1, "2"])).to eq(["2", 1])
1 example, 0 failures
但通常情况并非如此,因为测试中的预期值应该在 里面,它表示 DB 中的值:expect(...)
expect(["2", 1]).to eq(Bag.new([1, "2"]))
Failure/Error: expect(["2", 1]).to eq(Bag.new([1, "2"]))
expected: [1, "2"]
got: ["2", 1]
(compared using ==)
1 example, 1 failure
这背后的原因是,这是调用的,而不是我的自定义方法。Array#==
Bag#==
我查看了它所说的文档(https://devdocs.io/ruby~3.2/array#method-i-3D-3D)
如果 array.size == other_array.size 和 array 中的每个索引 i array[i] == other_array[i],则返回 true:
但在这里我停了下来,因为我无法弄清楚如何实现特定索引的值的获取。我尝试实现 Bar#[]
和 Bar#fetch
,但在比较对象时没有调用它们。
也许这根本不可能,因为数组调用了一些无法覆盖的低级 C 函数。但也许有人知道解决方案。
答:
我当然可以停止比较整个哈希值
您可以继续比较整个哈希值。RSpec 是非常强大的工具
RSpec 允许您直接在预期代码中使用其匹配器 DSL
因此,为什么不使用此功能呢?
此外,还有一个功能,我没有找到详细的文档:
RSpec.describe do
let(:hsh) { { foo: ["test", { bar: [1,2,3] }] } }
it 'check nested hashes well' do
expect(hsh).to match(foo: contain_exactly("test", match(bar: contain_exactly(1, 2, 3))))
end
end
此处,并在预期输出中使用。当然,您可以使用 like 或任何其他匹配器match
contain_exactly
match_array
match_array([1, 2, 3])
我会像这样使用嵌套:match
match_array
it 'matches when nested arrays having different sorting' do
data = { foo: ['test', { bar: [3, 2, 1] }] }
expect(data).to match(
{ foo: ['test', bar: match_array([1, 2, 3])] }
)
end
评论