0
0

allow(Kernel).to receive(:sleep)でsleepメソッドをmockできない場合の対処法

Last updated at Posted at 2024-07-13

解決したいこと

RSpecでテストを実行するとき、実装に含まれているsleepメソッドで待機時間が発生し、テストの実行時間が増大してしまうので対処したい。

具体例

Sample#testについてテストする例。

lib/sample.rb
class Sample
  def test
    sleep 10
  end
end

sleepメソッドはKerenlクラスのメソッドなので、Kernelクラスでmockしようとしてみる。

spec/lib/sample_spec.rb
require_relative '../../lib/sample'

describe Sample do
  it 'not to sleep' do
    allow(Kernel).to receive(:sleep)

    expect { sample.test }.to_not raise_error
  end
end

しかし、テストを実行してみると、Finished in 10.01 secondsと時間がかかる。

$ bundle exec rspec spec/lib/sample_spec.rb
.

Finished in 10.01 seconds (files took 0.06606 seconds to load)
1 example, 0 failures

解決方法

Sampleのインスタンスに対してallowで振る舞いを教える。

spec/lib/sample_spec.rb
require_relative '../../lib/sample'

describe Sample do
  it 'not to sleep' do
    sample = Sample.new
    allow(sample).to receive(:sleep)

    expect { sample.test }.to_not raise_error
  end
end

今度はテストを実行してみると、inished in 0.00965 secondsとすぐに完了した。

$ bundle exec rspec spec/lib/sample_spec.rb
.

Finished in 0.00965 seconds (files took 0.05652 seconds to load)
1 example, 0 failures

sleepメソッドの振る舞いを上書きする

完全にはsleepさせたくない場合に、and_wrap_originalで振る舞いを変更できる。

spec/lib/sample_spec.rb

require_relative '../../lib/sample'

describe Object do
  it 'not to sleep' do
    sample = Sample.new
    allow(sample).to receive(:sleep).and_wrap_original { |method, _| method.call(0.5) }

    expect { sample.test }.to_not raise_error
  end
end

上記の例では、sleepメソッドに渡す引数が何であっても0.5秒待つようになる。実行してみると、約0.5秒かかっていることがわかる。

% bundle exec rspec spec/lib/sample_spec.rb
.

Finished in 0.50638 seconds (files took 0.05306 seconds to load)
1 example, 0 failures

なぜこれでmockできるのか?(調査中)

調査次第追記します。

参考元

こちらの記事を参考にさせていただきました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0