個人的にいいなと思ったgemの紹介です。
今後もいいgemを見つけたら記事にしていきたいと思います。
ファイル操作のテストは面倒
やったことがある人はわかるとは思いますがファイルやディレクトリを作成、削除したり、パーミッションを変更したりのテストは意外と気を使います。
例を挙げると
- 作成したファイルの後片付け
- テスト対象のコードのバグによる想定しない場所へのファイル作成、削除
などです。
特にファイルの削除を間違ってしてしまと取り返しがつかなくなってしまう場合もあります。
memfs
memfsはファイル操作をメモリ上で完結してくれるライブラリです。ハードドライブを操作することがないので余計なファイルが生まれたり消してはいけないファイルを消してしまうことがありません。
実現方法は以下のようになっています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# https://github.com/simonc/memfs/blob/master/lib/memfs.rb#L86
def activate!(clear: true)
Object.class_eval do
remove_const :Dir
remove_const :File
remove_const :IO
const_set :Dir, MemFs::Dir
const_set :IO, MemFs::IO
const_set :File, MemFs::File
end
MemFs::FileSystem.instance.clear! if clear
end
|
至って単純でRubyの標準ライブラリを置き換えています。
使用例
学習テストを書いたのでそこからいくつか抜粋します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
def test_pwd
MemFs.activate do
assert_equal('/', Dir.pwd)
end
end
def test_ls
MemFs.activate do
assert_equal([], Dir.glob('*'))
end
end
def test_system
MemFs.activate do
assert_not_equal('', `ls`)
end
end
def test_list_mkdir
dirs = %w[/test1 /test2]
MemFs.activate do
FileUtils.mkdir(dirs)
dirs.each do |dir|
assert_true(File.directory?(dir))
end
end
dirs.each do |dir|
assert_false(File.directory?(dir))
end
end
def test_ln_s
MemFs.activate do
dir = '/tmp/test1'
link = '/tmp/test1_link'
FileUtils.mkdir(dir)
FileUtils.ln_s(dir, link)
assert_true(File.symlink?(link))
end
end
def test_chmod
MemFs.activate do
dir = '/tmp/test1'
FileUtils.mkdir(dir, mode: 0o755)
stat = File.stat(dir)
assert_equal(0o100755, stat.mode)
FileUtils.chmod(0o644, dir)
stat = File.stat(dir)
assert_equal(0o100644, stat.mode)
end
end
|
ディレクトリの作成、削除や、シンボリックリンク、パーミッション系もカバーしているようです。
もっと複雑な場面になるとわかりませんが、単純な操作はこれを使って安全にテストできそうです。
注意点
test_pwd
、 test_ls
からわかりますが、 MemFs.activate
のブロック内はなんのファイルも存在しない /
がpwdになるので、必要なファイル、ディレクトリはブロック内で作成する必要があります
test_system
の通り、rubyの File
、 Dir
、 IO
を介していないsystem系のコマンドでは当然ハードディスクをいじれるので、そういったコマンドを使用している場合は注意しましょう
まとめ
ファイル操作がある時に使ってみようと思います。
他の言語でも似たようなライブラリ欲しいですが、割とゴリ押しなので同じような方法を使うのは柔軟な言語でないと厳しそうですね。