約束の地

キャロの想い出

Test::Unit でデータを投入してテストをする

Test::Unit

Ruby の Test::Unit で具体的なデータを入れてテストをする方法です。いわゆるデータドリブンなテストってやつです。

解説ページ

とはいえ、すでに素晴らしい記事があります。以下のページを読むとだいたい分かってしまいます。

Ruby用単体テストフレームワークtest-unitでのデータ駆動テストの紹介 - ククログ(2013-01-23)

具体例

しかしながら、試行錯誤をして手を動かさないと小一時間悩んでしまうかもしれません*1ので、具体例を挙げて補足してみます。上記ページと一緒に読むとよいです。

書くコードのまとめ

以下の点を踏まえてコードを書きます。

  • dataメソッド(特異メソッド)にブロックを渡すことでテストデータを定義する
  • dataメソッドはそのテストデータを利用する直前に実行されなければいけない
  • dataメソッドに渡すブロックは、「テストデータ」を「値」、そのテストデータに対して名付けた名前を「キー」とする

具体的なコード

コードを見た方が早いので載せます。このコードは以下のようにテストをしようとしています。

  • test_remove_linefeedというテストメソッドのために直前でdataメソッドを実行しテストデータを生成している
  • test_remove_linefeedメソッドにはdataという引数を渡す(引数名はdataでなければいけない)
  data do
    linefeed_data = {}
    linefeed_data["cr_and_lf"] = [
      "<br>",
      {
        linefeed: "\r\n",
      },
    ]
    linefeed_data["lf"] = [
      "<br>",
      {
        linefeed: "\r",
      },
    ]
    linefeed_data["cr"] = [
      "<br>",
      {
        linefeed: "\n",
      },
    ]
    linefeed_data
  end
  def test_remove_linefeed(data)
    expected, test_linefeed = data
    assert_equal expected, test_linefeed[:linefeed].gsub(/(\r\n|\r|\n)/, "<br>")
  end

上記のテストデータでは、3種類のテストデータを定義しています。cr_and_lflfcrです。そして3つの種類のテストデータそれぞれで、「期待される結果(一つ目の要素)」と「テストに実際に投入するデータ(二つ目の要素)」を取っています。

cr_and_lfのテストデータ」の場合では、「期待される結果」は"<br>"です。「テストに実際に投入するデータ」は{ linefeed: "\r\b" }です。

3つの種類のテストデータをlinefeed_dataというハッシュにおさめています。この3つの種類のテストデータをひとつのパックにしています(dataメソッドにおいてブロックで渡している)。そのパックをtest_remove_linefeedメソッドに引数で渡しています。

テストメソッド内での挙動

test_remove_linefeedメソッドないでの挙動です。

まず1行目で引数のdataを、「期待される結果」と「テストに実際に投入するデータ」の配列に分割しています。この分割により、それぞれの配列は次のような値を取ります。

  • expected["<br>", "<br>", "<br>"]
  • test_linefeed[{ linefeed: "\r\n" }, { linefeed: "\r" }, { linefeed: "\n" }]

となると二行目のassert_equalの内容については自明かと思います。テストデータとして投入された"\r\n""\r""\n"の3つの値がそれぞれ全て"<br>"に置換されているかどうかをテストしています。上記のテストはパスすることが確認できます。

補足

テストデータの構成

上記の例では「3種類のテストデータ」を定義する際に「期待される結果」と「テストデータ」を代入していました。しかし、「期待される結果」は省略することが可能です。

テストデータの「名前」

上記の例におけるcr_and_lflfcrという名前はコード上で扱うことはありません*2。テストデータはdataにパックされ、コード上で扱う場合は「配列」になるためです。

ではどのような場面でこの命名が現れるのかというと、テストのログが出力されるときです。たとえばエラーで以下のような形で表示されます。

=======================================================================================================
Error: test_remove_linefeed[cr_and_lf](TestMyClass): TypeError: no implicit conversion of String into Integer
......
......
......
=======================================================================================================

*1:というか悩みました

*2:例えば、ハッシュのキーとして扱うことはありません

Powered by はてなブログ