Ruby の test-unit で特定のテストだけ実行する

fluentd plugin を作ろうとしたところ、fluentd では test-unit でテストを書くことを推奨しているので test-unit でテストを書こうとしたんですが、ネット上に溢れている情報では test メソッドを使って定義したテストの実行方法や rake task 経由で指定する方法について言及されているものが見つからなかったのでまとめてみました。

Fluentd core project strongly recommends to use test-unit as a unit test library.

cf. Writing plugins | Fluentd

test-unit の情報源

公式ページは http://test-unit.github.io/ で、テストケースの書き方については Test::Unit::TestCase のドキュメント を読むのが良さそうです。

日本語のページだと Test::Unitでテストを書く - Qiita がとても参考になります。

特定のテストの実行の仕方については test-unitで指定したテストだけ実行する方法 - Qiita が参考になります。自分のググり力が低いのか、英語だとこれだけの情報がまとまっているものは見つかりませんでした。

test-unit で定義した特定のテストを実行する方法

次のようなファイルを考えます。

require "test-unit"

class MyTest < Test::Unit::TestCase
  def test_write
    puts "test_write"
  end

  test "write" do
    puts "write"
  end

  sub_test_case "with a certain option true" do
    test "write" do
      puts "with a certain option true: write"
    end

    test "try_write" do
      puts "with a certain option true: try_write"
    end
  end
end

test_write だけ実行する

-n オプションにメソッド名を指定します。

% ruby -I test /path/to/test.rb -v -n 'test_write'
Loaded suite /path/to/test
Started
MyTest:
  test_write:                                                           test_write
.: (0.000288)

Finished in 0.00103 seconds.
-------------------------------------------------------------------------------------------
1 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-------------------------------------------------------------------------------------------
970.87 tests/s, 0.00 assertions/s

全ケースの test “write” だけ実行する

-n オプションに test: DESCRIPTION の形式で値を指定します。

% ruby -I test /path/to/test.rb -v -n 'test: write'
Loaded suite /path/to/test
Started
MyTest:
  test: write:                                                          write
.: (0.000280)
  with a certain option true:
    test: write:                                                        with a certain option true: write
.: (0.000289)

Finished in 0.00118 seconds.
-------------------------------------------------------------------------------------------
2 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-------------------------------------------------------------------------------------------
1694.92 tests/s, 0.00 assertions/s

これは test メソッドを使ってテストを定義すると test: DESCRIPTION の形式でメソッドが定義されるからです。

特定のケースだけ実行する

-t オプションに TESTCASE::SUB_TESTCASE_DESCRIPTION の形式で値を指定します。

% ruby -I test /path/to/test.rb -v -t 'MyTest::with a certain option true'
Loaded suite /path/to/test
Started
MyTest:
  with a certain option true:
    test: try_write:                                                    with a certain option true: try_write
.: (0.000452)
    test: write:                                                        with a certain option true: write
.: (0.000198)

Finished in 0.001285 seconds.
-------------------------------------------------------------------------------------------
2 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-------------------------------------------------------------------------------------------
1556.42 tests/s, 0.00 assertions/s

これは sub_test_case メソッドを使うと name メソッドでこのような形式の値を返すクラスが定義されるからです。-t オプションを指定した場合は match_test_case_name メソッドによってマッチするかの判定が行われ、これに name メソッドが使われます。

なお、-n オプションも -t オプションも / で括ることで正規表現を使うことができるので、今回のケースでは次のように簡略化して書くこともできます。

% ruby -I test /path/to/test.rb -v -t '/with a certain option true/'
Loaded suite /path/to/test
Started
MyTest:
  with a certain option true:
    test: try_write:                                                    with a certain option true: try_write
.: (0.000639)
    test: write:                                                        with a certain option true: write
.: (0.000236)

Finished in 0.001906 seconds.
-------------------------------------------------------------------------------------------
2 tests, 0 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-------------------------------------------------------------------------------------------
1049.32 tests/s, 0.00 assertions/s

rake task で特定のテストを実行する方法

TESTOPTS 環境変数に test-unit のオプションを指定すれば良いです。ただし、-n 'test: write' のようにスペースを空けるとファイル名として認識して File does not exist というエラーになるので注意してください。

よって、test: write を実行するには次のどちらかのように指定することになります。

rake test TESTOPTS="-n'test: write'"
rake test TESTOPTS="--name='test: write'"