2017-01-22 8 views
0

私は私はいくつかの目標をモジュールのプライベートセクションでは、以下の方法...Rspec 3.5のモジュールでカーネルスリープメソッドをテストするには?

def add_api_delay 
    sleep(retry_delay * (retry_multiplier_adjustment - retries)) if retries.positive? 
    end 

私はこれまでのところ、このようなルックスで働いていますスペック...

let!(:klass) do 
    Class.new do 
     include AmazonMws::Shared::Utilities 
     attr_accessor :retries, :retry_multiplier_adjustment, :retry_delay 
     def initialize 
     @retries = 1 
     @retry_delay = 1 
     @retry_multiplier_adjustment = 2 
     end 

     def test_add_api_delay 
     add_api_delay 
     end 
    end 
    end 

    describe '.add_api_delay', focus: true do 
    # let(:kernel_spy) { class_spy(Kernel, sleep: true) } 

    before do 

    end 

    it 'sleeps retry api calls' do 
     # allow(klass).to receive(:sleep).with(1).and_return(kernel_spy) 
     # expect(kernel_spy).to have_received(:sleep) 
     # expect(Kernel).to receive(:sleep).with(1) 
     expect(Kernel).to receive(:sleep).and_return(true) 
     klass.new.test_add_api_delay 
    end 
    end 

を持っています私はこのプライベートメソッドをテストしたいのですが、どのようにスリープが呼び出されたかを確認する方法があります。私はスイートを遅くしたくないので理想的にはKernelに対してクラススパイを使用しようとしています。私がテストしているものは何も動作していないようです。

UPDATE

describe '.add_api_delay' do 
    before do 
     allow_any_instance_of(klass).to receive(:sleep).and_return(1) 
    end 

    it 'sleeps retry api calls' do 
     expect(klass.new.test_add_api_delay).to eq(1) 
    end 
    end 

この作品は、しかし、それは以下の警官、それのフラグとして理想的ではありません...

C: RSpec/AnyInstance: Avoid stubbing using allow_any_instance_of 
     allow_any_instance_of(klass).to receive(:sleep).and_return(1) 

あなたの考えは何ですか?

答えて

1

あなたは正しいことに期待を寄せているわけではないので、私はそれがうまくいかないと思います。あなたはKernelにそれを入れてみました、そしてテスト対象のクラスにしたようですが、あなたは、インスタンスの上に置く必要があります。

it 'sleeps retry api calls' do 
    thing = klass.new 
    allow(thing).to receive(:sleep) 

    thing.test_add_api_delay 

    expect(thing).to have_received(:sleep).with(1) 
end 

は、上記のテストは、それが下のクラスをスタブされていることで臭いましたテスト。しかし、おそらくsleepを呼び出すだけで、ここでいくつかのデザイン制約を適用し、Rubyの優雅さを失うことよりも優れていると思います。

+0

Timさん、ありがとうございました。 –

0

あなたは

RSpec.describe "allow_any_instance_of" do 
    it "returns the specified value on any instance of the class" do 
    allow_any_instance_of(Object).to receive(:foo).and_return(:return_value) 

    o = Object.new 
    expect(o.foo).to eq(:return_value) 
    end 
end 
+0

私はそれについて考えていましたが、それはhttps://github.com/backus/rubocop-rspec –

0

allow_any_instace_of使用する必要があります。ここ睡眠を呼び出すプライベートメソッドのRSpecのテストの最小限の例です。

class Sleeper 
    def initialize(delay:) 
    @delay = delay 
    end 
    attr_reader :delay 

    private 

    def rest 
    sleep delay 
    end 
end 

require 'rspec' 

RSpec.describe Sleeper do 
    let(:sleeper) { Sleeper.new(delay: delay) } 
    let(:delay) { 10 } 

    # Comment here explaining why this test is necessary 
    describe '.send :rest' do 
    before { allow_any_instance_of(Sleeper).to receive(:sleep) } 

    it 'sleeps' do 
     expect(sleeper).to receive(:sleep) 
     sleeper.send :rest 
    end 
    end 
end 

UPDATE:

あなたがここに意思決定をしなければなりません。

「スタブを避ける」というRubocopのアドバイスは良いアドバイスですが、プライベートメソッドがカーネルメソッドを使用しているかどうかをテストする理由があったとしたら、スタブするのが最良の方法です。これらのテストの理由がRubocopの純度よりも重要である場合は、Rubocopの警告を無視する必要があります。

Rubocopのアドバイスが重要な場合は、遅延を計算するパブリックメソッドを作成し、そのテストを記述することをお勧めします。たぶんのようなもの:この第2のケースで

def retry_delay_duration 
    return 0 if retries < 1 
    retry_delay * (retry_multiplier_adjustment - retries) 
end 

private 

def add_api_delay 
    sleep retry_delay_duration 
end 

、あなたはadd_api_delayのテストを削除し、唯一の公共法retry_delay_duration(または何でもあなたはそれを呼び出す)をテストする必要があり、正しい遅延を返します。

+0

からの警察に失敗しました。この提案は機能していません。他のアイデアはありますか? –

+0

しかし、開発者が睡眠をコメントアウトしたり、睡眠を置き換えたりすると、その睡眠はカバーされますか?また、 "allow_any_instance_of"を使用することは貧弱な習慣であると私は理解しています。 –

+0

あなたはあなたの意図を認識し、所有しなければなりません。このようにテストすることは "実装"テストであり、ビジネスケースがあれば貧弱な方法ではありません。確かに、Rubyはこの種の制約を作る上での偉大な言葉ではありませんが、私たちはすべて自分たちが持っているものとやらなければなりません。この例では、オブジェクトは任意の長さのランタイムを停止する機能を持っています(実際のコードでは、何らかの最大持続時間を設定しています)。もしあなたがそれをしているのであれば、それを取り巻く何らかの実装テストをするのが賢明だと思います。それは脆いですが、あなたはジョブキューを使用し始めるときにそれをリファクタリングします。 – wobh

関連する問題