web-dev-qa-db-ja.com

rspecのdoubleメソッドとは何ですか?

Rspec docには、テストダブルを作成するためにdoubleメソッドを使用する必要があると記載されています。しかし、doubleを使用しなくても、問題なく動作することがわかります。 doubleを使用しないことに問題はありますか?ダブルを使用していない場合、MyClassstubおよびその他のrspecメソッドを取得する方法もありますか? rspecで実行する場合、すべてのオブジェクトで使用できますか?

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
38
grafthez

編集:私はあなたの質問を読み直しただけで、私はまったく答えていませんでした。それは関連しているので、元の答えを残しますが、あなたの具体的な答えはここにあります:

Doubleを必要としない理由は、インスタンスメソッドではなくクラスメソッドをスタブ化するためです。 doubleは、クラス自体ではなく、クラスのインスタンスを処理する場合にのみ役立ちます。

もう少し二重を説明する古い答え:

可能であれば、テストダブルの代わりに常に実際のクラスを使用する必要があります。これにより、より多くのコードが実行され、テストがより包括的になります。テストダブルは、実際のオブジェクトを使用できない、または使用すべきでない状況で使用されます。たとえば、外部リソース(ネットワークやデータベースなど)にヒットすることなくクラスをインスタンス化できない場合、または多数の依存関係がある場合、それを使用するものをテストするだけの場合は、 doubleとdoubleのいくつかのメソッドをスタブします。

以下に、より具体的な例を示します。MyClassをテストしているとしましょう。しかし、MyClassをインスタンス化するには、FooLoggerを渡す必要があります。

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

FooLogger.newは、syslogソケットを開き、すぐにスパムを開始します。テストを実行するたびに、ログが記録されます。このテスト中にログをスパム送信したくない場合は、代わりにFooLoggerのdoubleを作成し、そのメソッドをスタブアウトできます:

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

よく設計されたクラスのほとんどは副作用なしでインスタンス化できるため、通常はdoubleの代わりに実際のオブジェクトを使用し、その代わりにスタブメソッドを使用できます。クラスにはインスタンス化を困難にする多くの依存関係がある他のシナリオがあります。また、doublesは、問題を乗り越えて、本当に気になることをテストする方法です。

私の経験では、doubleを使用する必要があるのはコードの匂いですが、私たちは簡単に変更できないクラス(たとえば、gemから)を使用しなければならないことが多いので、時々必要になるツールです。

43
Jim Stewart

RSpec Mocks 3.0では、doubleの動作が変更されました。 verify doubles 、つまり、「RSpecは、スタブ化されているメソッドが、使用可能な場合、基礎となるオブジェクトに実際に存在することを確認します」が、「基礎となるオブジェクトまたはクラスが定義されていません"。

Doublesを検証すると、double型(インスタンス、クラス、オブジェクト、動的クラス、パーシャル)に固有であることが要求されます。以下に、インスタンス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
0