2013-03-06 104 views
36

在rspec文档中指出,我应该使用double方法来创建测试双。 但是我可以看到,即使我不使用double,它也能正常工作。没有使用double有什么问题吗?另外,如果我不使用双如何MyClass得到stub和其他rspec方法?它们在rspec中运行时是否可用于所有对象?rspec中的double方法是什么?

require 'spec_helper' 

class MyClass 

    def self.run 
     new.execute 
    end 

    def execute 
     'foo' 
    end 

end 

describe MyClass do 

    it 'should stub instance method' do 
     obj = MyClass.new 
     obj.stub(:execute).and_return('bar') 
     obj.execute.should == 'bar' 
    end 

    it 'should stub class method' do 
     MyClass.stub(:run).and_return('baz') 
     MyClass.run.should == 'baz' 
    end 

end 

回答

40

编辑:我刚刚重读你的问题,并意识到我没有完全回答它。留下我原来的答案,因为它是相关的,但这里是你的具体答案:

你不需要双重的原因是因为你是存根类方法,而不是实例方法。 double仅用于处理类的实例,而不是类本身。

解释一倍多一些

老答案:

你应该总是当你可以用它代替试验双打真正的类。这将更多地运用你的代码并使你的测试更全面。测试双打用于你不能或不应该使用真实物体的情况。例如,如果一个类不能在没有外部资源(如网络或数据库)的情况下实例化,或者具有大量的依赖关系,而只是测试使用它的某些东西,则可能需要创建一个双重和存根一些方法在双。

这里有一个更具体的例子:假设您正在测试MyClass,但为了实例MyClass,你需要在FooLogger经过:

mylogger = FooLogger.new 
myclass = MyClass.new logger: mylogger 

如果FooLogger.new打开系统日志插座,并开始发送垃圾邮件的权利每当你运行测试时,你都会记录下来。如果你不希望这个测试过程中,以垃圾邮件的日志,可以代替一个双重的FooLogger和存根出它的方法:

mylogger = double(FooLogger) 
mylogger.stub(:log) 
myclass = MyClass.new logger: mylogger 

因为大多数设计良好的类可以无任何副作用被实例化效果,你通常可以使用真实的对象而不是双重的,而stub方法。还有其他一些场景,其中类有很多依赖关系,使它们难以实例化,而双打是一种通过彻底检查并测试你真正关心的事情的方式。

根据我的经验,需要使用double是代码气味,但我们经常需要使用不易更改的类(例如,从宝石中),所以它是您不时需要的工具。

+0

其实当你在看我的例子,第一个规范存根**实例方法**,第二个存根**类方法**。它看起来像两个工作正常,没有使用'双'之前使用。这就是为什么我想知道什么是一个额外的'双'给我的魔法。 – grafthez 2013-03-06 17:45:00

+0

看看我创建的https://gist.github.com/anonymous/5101448这个例子。如果我想测试'SchedulerJob',我需要存根'RequestSchedule'并模拟'RequestToQueuePusher'吗?另外困扰我的是'SchedulerJob'与两个剩余的类紧密结合。当我来自Java世界时,我通常会将它们作为依赖项提取,因为没有简单的方法来伪造以硬编码方式创建的对象。在Ruby中,它似乎不是一个问题。我看到很多像“SchedulerJob”这样的对象。我知道有一种方法可以很容易地伪装它们,但对我来说,这违反了一些固体原理 – grafthez 2013-03-06 18:06:15

+0

这也是Ruby世界中糟糕的设计。应该有一种方法来注入RequestSchedule依赖关系,以便于测试。你可以这样做:'fakeschedule = double(RequestSchedule); RequestSchedule.stub(新).and_return(fakeschedule);'。它当然应该重构。 – 2013-03-06 18:42:00

0

随着RSpec Mocks 3.0双打的行为已经改变。您现在可能需要verify doubles,这意味着“RSpec将检查方法 被底层对象实际上是否存在于底层对象上”,但“如果未定义底层对象或类,则不会进行检查”。

验证双精度请求您具体了解double类型(实例,类,对象,动态类,部分)。下面是来自RSpec Relish一个实例双例子:

RSpec.describe User, '#suspend!' do 
    it 'notifies the console' do 
    notifier = instance_double("ConsoleNotifier") 

    expect(notifier).to receive(:notify).with("suspended as") 

    user = User.new(notifier) 
    user.suspend! 
    end 
end 
相关问题