1

我有嘲笑的问题。我有类 DistanceMatrix,我想指出在 if/else 语句中调用了哪个方法 form_matrix。我需要使用 mocha 和 RSpec。有任何想法吗?

class DistanceMatrix

 def initialize(*args)
    if args[0].class == String
      form_matrix(get_data_from_yaml(args[0], args[1]))
    elsif args[0].class == Array || args[0] == nil
      form_matrix(get_data_from_db(args[0]))
    end
 end

 def form_matrix(...)
  ...
 end

end

它尝试过:

describe DistanceMatrix, "when mocking ..." do
  it "should do call form_matrix" do
    DistanceMatrix.any_instance.expects(:form_matrix).with([1]).once
    DistanceMatrix.any_instance.expects(:get_data_from_yaml).with("file_name.yml").once.returns([1])
    DistanceMatrix.new("file_name.yml")
  end
end

但出现错误:

Failures:
  1) DistanceMatrix when mocking ... should do call form_matrix
     Failure/Error: DistanceMatrix.new("file_name.yml")
     unexpected invocation: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml', nil)
     unsatisfied expectations:
     - expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml')
     - expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.form_matrix([1])
     satisfied expectations:
     - allowed any number of times, already invoked once: #<DistanceMatrix:0x9e48b40>.get_optimal_route(any_parameters)
     - allowed any number of times, already invoked once: #<Database::Distances:0x9d59798>.load_distances(any_parameters)
     # ./distance_matrix.rb:18:in `initialize'
     # ./tsp_algorithm_spec.rb:253:in `new'
     # ./tsp_algorithm_spec.rb:253:in `block (2 levels) in <top (required)>'
Finished in 0.25979 seconds

我发现在 RSpec 中我们不应该使用 .expects() 而是 .should_receive(),所以我尝试了:

describe DistanceMatrix, "when mocking ..." do
  it "should do call form_matrix" do
    DistanceMatrix.any_instance.should_receive(:form_matrix).with([1])
    DistanceMatrix.any_instance.should_receive(:get_data_from_yaml).with("file_name.yml").and_return([1])
    DistanceMatrix.new("file_name.yml")
  end
end

但有新的失败:

Failures:
  1) DistanceMatrix when mocking ... should do call form_matrix
     Failure/Error: DistanceMatrix.any_instance.should_receive(:form_matrix).with([1])
     (#<Mocha::ClassMethods::AnyInstance:0x96356b0>).form_matrix([1])
         expected: 1 time
         received: 0 times
     # ./tsp_algorithm_spec.rb:251:in `block (2 levels) in <top (required)>'

Finished in 0.26741 seconds
4

2 回答 2

4

我只有使用 Mocha 而不是 RSpec 的经验,但是查看 Mocha 失败消息,关键部分是:-

unexpected invocation: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml', nil)
unsatisfied expectations:
- expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml')

如果您查看这些行的末尾,您会注意到get_data_from_yaml没有使用预期的参数调用它。它被调用('filename.yml', nil)而不是('filename.yml')像预期的那样。

发生这种情况是因为当您仅使用一个DistanceMatrix.new("file_name.yml")参数调用测试然后使用内部调用时,并且由于是单个元素数组,因此将是.DistanceMatrix#initialize DistanceMatrix#get_data_from_yaml(args[0], args[1])argsargs[1]nil

也许这不是您期望 Ruby 工作的方式,但以下演示了这种行为:-

def foo(*args)
  puts "args[0]=#{args[0].inspect}; args[1]=#{args[1].inspect}"
end

foo("string") # => args[0]="string"; args[1]=nil
于 2010-12-04T17:26:33.227 回答
0
DistanceMatrix.any_instance.expects(:form_matrix).with("String") # => supply the correct string param

或者

DistanceMatrix.any_instance.expects(:form_matrix).with([]) # => supply the correct array param

我不确定你的 get_data_from_db 和 get_data_from_yaml 方法在做什么,但你应该能够控制这些输入以及验证是否向 form_matrix 提供了正确的参数。

已编辑 您必须使用 DistanceMatrix.any_instance 而不是模拟实例变量,因为您试图在初始化程序中模拟某些东西。此外,如果不清楚,您需要在上面几行中设置模拟后实际进行适当的方法调用,例如

DistanceMatrix.new("SomeString")

已编辑

it "should do call #form_matrix with proper arguments" do
  DistanceMatrix.any_instance.expects(:form_matrix).with([1])
  DistanceMatrix.any_instance.expects(:get_data_from_yaml).with("foo").returns([1])
  DistanceMatrix.new("foo")
end
于 2010-12-01T19:06:48.130 回答