我正在从FactoryGirl中解放自己(至少在lib文件夹中)。所以,我开始编写像“mock”和“stub”这样的奇怪的东西。有人可以帮助新手吗?
我有这个模块
module LogWorker
extend self
def check_todo_on_log(log, done)
if done == "1"
log.todo.completed = true
log.todo.save!
elsif done.nil?
log.todo.completed = false
log.todo.save!
end
end
end
log
和todo
是具有todo :has_many logs
关联的rails模型。但是在使用存根和模拟时这应该无关紧要,对吗?
我尝试了很多东西,但是当我将模拟传递给方法时没有任何反应,
describe LogWorker do
it 'should check_todo_on_log'do
todo = mock("todo")
log = mock("log")
log.stub!(:todo).and_return(todo)
todo.stub!(:completed).and_return(false)
LogWorker.check_todo_on_log(log,1)
log.todo.completed.should eq true
end
end
Failures:
1) LogWorker should check_todo_on_log
Failure/Error: log.todo.completed.should eq true
expected: true
got: false
(compared using ==
我真的希望看到一些使用存根和/或模拟测试LogWorker.check_todo_on_log方法的规范。
答案 0 :(得分:1)
首先,您的check_todo_on_log
方法非常糟糕。永远不要使用字符串作为选项,特别是当字符串为“1”时。此外,如果你传递“2”,没有任何反应。我会假设它只是一种局部方法,而你的代码并不是那样的:P
查看代码,您有三个主要问题。首先,你打电话给LogWorker.check_todo_on_log(log,1)
。这不会做任何事情,因为当第二个参数是字符串"1"
或nil时,您的方法只会执行操作。其次,你存根todo.completed
所以它总是返回false:todo.stub!(:completed).and_return(false)
。然后测试它是否为真。显然这会失败。最后,您不要模拟save!
方法。我不知道代码实际上是如何为你运行的(它对我不起作用)。
下面是我如何编写你的规范(注意他们正在测试奇怪的行为,因为check_todo_on_log
方法也很奇怪)。
首先,有一种更简单的方法可以将模拟方法添加到模拟对象中。您可以将键和值传递给mock
方法,它们将自动创建。
接下来,我将模拟放入let
块。这使得每次测试都可以轻松地重新创建它们。最后,我为函数的每个可能行为添加了一个测试。
# you won't need these two lines, they just let the code be run by itself
# without a rails app behind it. This is one of the powers of mocks,
# the Todo and Log classes aren't even defined anywhere, yet I can
# still test the `LogWorker` class!
require 'rspec'
require 'rspec/mocks/standalone'
module LogWorker
extend self
def check_todo_on_log(log, done)
if done == "1"
log.todo.completed = true
log.todo.save!
elsif done.nil?
log.todo.completed = false
log.todo.save!
end
end
end
describe LogWorker do
let(:todo) { mock("Todo", save!: true) }
let(:log) { mock("Log", todo: todo) }
describe :check_todo_on_log do
it 'checks todo when done is "1"'do
todo.should_receive(:completed=).with(true)
LogWorker.check_todo_on_log(log,"1")
end
it 'unchecks todo when done is nil'do
todo.should_receive(:completed=).with(false)
LogWorker.check_todo_on_log(log,nil)
end
it "doesn't do anything when done is not '1' or nil" do
todo.should_not_receive(:completed=)
LogWorker.check_todo_on_log(log,3)
end
end
end
注意我是如何使用基于行为的测试的?我没有测试mock上的属性是否有值,我正在检查是否在其上调用了适当的方法。这是正确使用模拟的关键。