Ruby
RSpec

FileUtils::DryRunを使ってテストする

TL;DR

remove_constconst_set(or 定数代入)を使ってFileUtilsFileUtils::DryRunにすり替えて、stderrに吐き出されるメッセージを確かめる。

準備

spec_helpr.rbやモックを行う場所に以下のコードを書きます。

Object.class_eval do
  RealFileUtils = FileUtils
  remove_const(:FileUtils)
  FileUtils = RealFileUtils::DryRun
end

FileUtilsFileUtils::DryRunに差し替えています。

サンプル

実装コード

今回は以下のコードをテストしてみましょう。

sample.rb
class Sample
  def copy_gemfile
    FileUtils.copy("Gemfile", "CopyGemfile")
  end
end

FileUtils.copyを使ってGemfileというファイルをCopyGemfileにコピーしています。

テストコード

sample_spec.rb
RSpec.describe Sample do
  it do
    expect {
      Sample.new.copy_gemfile()
    }.to output("cp Gemfile CopyGemfile\n").to_stderr_from_any_process
  end
end

FileUtils::DryRunのソースを読むとstderrに出力されていることが分かったのでそのようなテストを書きます。

to_stderr_from_any_processがポイントです。to_stderrではFileUtils::DryRunの出力を捕捉できません(原因はよく分かってないです)。

FileUtils::DryRunにすり替えられているため、テストを走らせてもファイルのコピーは行われておらず、代わりにcopy Gemfile CopyGemfile\nというメッセージがstderrに出力されます。出力には最後に改行が入るため、注意です。

参考

FileUtilsFileUtils::DryRunに差し替える方法はFakeFSの以下の実装を参考にしました。

https://github.com/fakefs/fakefs/blob/master/lib/fakefs/base.rb

FakeFSの方ではremove_constconst_setを使っているようです。今回const_setを使わず代入を用いたことに深い意味はありません。

濫用はできませんが、応用が効きそうな手法ですね。