5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

rspecで"`"(バッククォート)によるコマンドの実行をスタブする

Last updated at Posted at 2016-07-07

例えばこんなコードがあったとして

class Directory

  def initialize(path)
    @path = path
  end

  def list
    `ls -1 #{@path}`.chomp.split("\n")
  end
end

listメソッドをテストしたいですが、実際にコマンドが実行できるように
ディレクトリやファイルを作るのは、ちょっと。。。なので
コマンド実行部分をスタブしたいです。

こうします

describe Directory do
  subject { dir.list }

  let(:dir) { described_class.new('/path/to/dir') }

  before do
    stdout = %w(file1 file2 file3).join("\n")
    allow(dir).to receive(:`) { stdout }
  end

  it { is_expected.to eq(%w(file1 file2 file3)) }
end

テスト対象のDirectoryのインスタンスに対して`(バッククォート)メソッドが呼ばれたら
stdoutを返すようにします。

なぜ自分自身(テスト対象のインスタンス)にスタブするのか

`メソッドは、Kernelモジュールのメソッドで、
DirectoryクラスのスーパークラスObjectKernelモジュールをincludeしているからです。

バリエーション

  • 複数のDirectoryクラスのインスタンスをテストで使う場合
allow_any_instance_of(described_class).to receive(:`) { stdout }
  • 全てのコマンド実行をスタブしたい場合
allow_any_instance_of(Kernel).to receive(:`) { stdout }

まとめ

最初`をクラスメソッドと勘違いして、allow(Kernel).to receive(:`)としていたので
テストを実行すると普通にコマンドが実行されるという、残念なことになっていました。

こういうテストを書かないといけないケースは稀かも知れませんが
知ってると役に立つかもしれません。

5
5
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
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?