用rspec匹配元素类数组的更简单的方法?

时间:2013-01-08 22:38:47

标签: ruby rspec

我想在包含数组的元素类上断言,我尝试了以下方法:

这不起作用,但看起来很好看和可读:

["String", :symbol, Object.new].should =~ [an_instance_of(String), an_instance_of(Symbol), an_instance_of(Object)]

但是给了我以下错误:

Failure/Error: ["String", :symbol, Object.new].should =~ [an_instance_of(String), an_instance_of(Symbol), an_instance_of(Object)]
   expected collection contained:  [#<RSpec::Mocks::ArgumentMatchers::InstanceOf:0x007f9e6a33dbe0 @klass=String>, #<RSpec::Mocks::ArgumentMatchers::InstanceOf:0x007f9e6a33dbb8 @klass=Symbol>, #<RSpec::Mocks::ArgumentMatchers::InstanceOf:0x007f9e6a33db68 @klass=Object>]
   actual collection contained:    ["String", :symbol, #<Object:0x007f9e6a33dca8>]
   the extra elements were:        ["String", :symbol, #<Object:0x007f9e6a33dca8>]

请注意,没有遗漏的元素。

这很有效,但看起来很讨厌:

["String", :symbol, Object.new].collect{|x| x.class}.should =~ [String, Symbol,Object]
  1. 有没有更好的方法断言同样的事情?
  2. 为什么第一种方式没有缺失元素?

2 个答案:

答案 0 :(得分:3)

您可以使用&:class代替块

["String",:symbol,Object.new].map(&:class).should =~ [String,Symbol,Object]

产生相同但更具可读性。

另外,我使用map这是collect方法的简短别名。

答案 1 :(得分:2)

第二部分的答案取决于你的断言“请注意,没有遗漏的元素。” 缺少元素。

此:

expected collection contained:  [#<RSpec::Mocks::ArgumentMatchers::InstanceOf:0x007f9e6a33dbe0 @klass=String>, #<RSpec::Mocks::ArgumentMatchers::InstanceOf:0x007f9e6a33dbb8 @klass=Symbol>, #<RSpec::Mocks::ArgumentMatchers::InstanceOf:0x007f9e6a33db68 @klass=Object>]

与此不同:

the extra elements were:        ["String", :symbol, #<Object:0x007f9e6a33dca8>]

第一个包含类实例的模拟对象,第二个包含类的实例。 instance_of匹配器不应该以这种方式使用,你会这样做吗?

["String", :symbol, Object.new].should =~ [respond_to(:gsub), respond_to(:intern), respond_to(:object_id)]

它没有意义,因为您应该测试数组 数组的内容每个都具有某种属性。你所做的就是混淆两个测试,这样做会导致两者都出现问题。

subject { instance }
["String", :symbol, Object.new].each do |thing|
  let(:instance) { thing.class }
    if instance.class == String
      it{ should respond_to(:gsub) }
    else #...

更像这样的东西,但我认为这仍然是代码/设计气味 - 为什么你会在同一个数组中有这样不同的东西?规范,测试和处理都很困难。