Rspec docには、テストダブルを作成するためにdouble
メソッドを使用する必要があると記載されています。しかし、double
を使用しなくても、問題なく動作することがわかります。 double
を使用しないことに問題はありますか?ダブルを使用していない場合、MyClass
がstub
およびその他の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
編集:私はあなたの質問を読み直しただけで、私はまったく答えていませんでした。それは関連しているので、元の答えを残しますが、あなたの具体的な答えはここにあります:
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から)を使用しなければならないことが多いので、時々必要になるツールです。
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