首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >模拟和存根。我不懂基本的东西

模拟和存根。我不懂基本的东西
EN

Stack Overflow用户
提问于 2013-06-07 17:55:56
回答 1查看 160关注 0票数 0

我正在将自己从FactoryGirl中解放出来(至少在lib文件夹中)。所以,我开始写一些奇怪的东西,比如"mock“和"stub”。有人能帮助一个新手吗?

我有这个模块

代码语言:javascript
运行
复制
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

logtodo是具有todo :has_many logs关联的rails模型。但在使用stub和mock时,这真的无关紧要,对吧?

我尝试了很多方法,但当我将mock传递给该方法时,什么也没有发生,

代码语言:javascript
运行
复制
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方法的规范。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-08 01:45:27

首先,你的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块中。这样就可以很容易地为每个测试重新创建它们。最后,我为函数的每个可能行为添加了一个测试。

代码语言:javascript
运行
复制
# 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上的属性是否有值,我是在检查是否对其调用了适当的方法。这是正确使用mock的关键。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16981242

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档