Techioz Blog

Ruby+Minitest を使用してパラメータ化されたテストを作成する可能性はありますか?

概要

最近、Ruby+Minitest を使用する自動テスト プロジェクトに取り組み始めました。提供した入力データの数と同じ回数 1 つのテストを実行できるかどうか疑問に思っています。

だから、私は次のようなものを持っています(コードはNDAの下にあるため、実際の例を提供することはできません)

def test_new_registrations
  result = process_new_entry(list_entries)
  assert(validator_method(result), result)
end

重要なのは、process_new_entry メソッド内にループがあることです。このループを削除して、list_entries にあるエントリの数だけこのテストを実行するだけです。

Java+Selenium の TestNG から、テスト メソッド内で入力データを 1 つずつ渡すデータプロバイダーを使用するという概念を思い出しました。 同様のアプローチをここで実装できる可能性はありますか?

解決策

あなたが持っている場合:

class MyTest
  TESTCASES = {
    # input => expected
    a: "a",
    b: "b",
    c: "c",
  }

  def test_testcases
    TESTCASES.each do |entry, expected|
      result = process_one(entry)
      assert(expected, result)
    end
  end
end

そして、実際に各ケースを独自のテストで実行したい場合は、次のようにします。

MyTest
  TESTCASES = {
    # input => expected
    a: "a",
    b: "b",
    c: "c",
  }

  TESTCASES.each do |entry, expected|
    define_method("test_testcase_#{entry}") do
      result = process_one(entry)
      assert(expected, result)
    end
  end
end

Java とまったく同じ構文が本当に必要な場合は、上記をライブラリに変換して、これが機能するようにすることが可能です。

testcase_parameters(TESTCASES) # left as an exercise to the reader
def test_testcase(entry, expected)
  assert(expected, process_one(entry))
end

しかし、それについてあまりにも間接的/抽象的であることに利点があるとは思えません。コードと実行状態を検査可能でデバッグしやすい状態に保ち、明示的に保つことをお勧めします。

class MyTest
  TESTCASES = {
    # input => expected
    a: "a",
    b: "b",
    c: "c",
  }

  def test_testcases
    results = TESTCASES.map do |entry, expected|
      result = process_one(entry)
      [entry, [expected, result]]
    end

    invalid_results = results.select { |e, (ex, res)| ex != res }

    # This is a very easy-to-breakpoint place in code, to easily view all results:
    # binding.pry

    assert_empty invalid_results # failure cases will be printed out by test output
  end
end