ネクストでレコメンドエンジン開発をしてる古川です。
rubyで、ファイルを読み込んで加工して別のファイルに出力というプログラムをよく書きます。 最近、rspec でテストを書くようになったのですが、beforeでテスト入力ファイルを作成し、 after で作成したテスト入力ファイル、テスト出力ファイルを削除、ということをしていました。
とりあえずは、これで問題なかったのですが、同時実行時や、実行時パス、パーミッションなど、 今後いろいろ問題になりそうで、いやだなと思っていたところ、Stack Overflowに、 まさに、それがやりたかったんだよ!という記事を見つけました。 StringIOを使えばよかったのですね。
記事は、読み込みテストだけでしたので、書き込みテストも追加してみました。
テスト対象クラス my_file_io.rb
class MyFileIo def run(path_src, path_dst) x = load(path_src) y = transform(x) save(y, path_dst) end def load(path) fp = ::File.open(path, 'r') data = [] fp.each do |line| line.chop! data.push(line.split("\t")) end fp.close data end def transform(x) x.map {|t| t.map {|s| s.gsub(/a/, 'b')}} end def save(y, path) fp = ::File.open(path, 'w') y.each do |x| fp.write(x.join("\t") + "\n") end fp.close end end
spec ファイル my_file_io_spec.rb
describe MyFileIo do let(:target) { MyFileIo.new } it '元ファイルのa が bに置き換わったファイルが作成されること' do path_src = 'src.tsv' path_dst = 'dst.tsv' data_src = [ ['a11', 'a12'], ['a21', 'a22'] ] data_dst = [ ['b11', 'b12'], ['b21', 'b22'] ] contents_src_file = (data_src.map {|x| x.join("\t")}).join("\n") + "\n" ::File.stub(:open) .with(path_src, 'r') .and_return(::StringIO.new((contents_src_file), 'r')) file_dst = ::StringIO.new('', 'w') ::File.stub(:open) .with(path_dst, 'w') .and_return(file_dst) ans = (data_dst.map {|x| x.join("\t")}).join("\n") + "\n" target.run(path_src, path_dst) file_dst.string.should eq(ans) end end
Stack Overflow いつも、お世話になってます。