21

MiniTest を使用してテストしたい電話番号で動作する Ruby 2.0 コードがあります。電話番号の引数を取り、それをテストする関数があります(アサートを含む)。その関数を呼び出すたびに、それを新しいテスト ケースにしたいと考えています。このようなもの:

listOfPhoneNumbersForTesting.each { |phone|   testphone phone }  

私が望まないのはこれです:

class test2125551212 < MiniTest::Unit::TestCase
    def t2125551212 
        testphone "2125551212"
    end
end

... 10 回、20 回、または 100 回繰り返して、各電話番号をテストします ...

もちろん、MiniTest::Unit::TestCase 内にループ コードを配置することもできますが、テストする電話番号の数に関係なく、テストケースは 1 つだけになり、それは好ましくありません。(また、アサートの 1 つが失敗した場合、それ以上の電話番号はテストされません。私はそれを望んでいません!) また、2 番目の形式は DRY に違反しているように見えます。すべて電話番号が含まれています。

どういうわけか、TestPhone という名前のクラスを 1 つ作成し、電話番号引数を使用してそれを作成し、それを MiniTest フレームワークに取り込むことができるはずだと感じています。しかし、うまくいくなら、setup()、Fixtures、メタプログラミング、またはそれ以外のものを喜んで使用します。

listOfPhoneNumbersForTesting.each { |phone|   TestPhone.new phone }

TestPhone は TestCase サブクラスであり、最終的に testphone を呼び出して作業を行います。

基本的に、私が欲しいのはこれです: 1. 電話番号の 1 つのリスト。リストに番号を追加すると、レポート出力にもう 1 つの TestCase が得られます。2. 1 つの電話番号に関連付けられたテストが失敗した場合でも、残りは引き続きテストされます。3. すべての電話番号は、複数のアサーションを含む同じテストを受けます。

どうもありがとう!

4

1 に答える 1

28

メソッドを動的に定義できます。

次の例では、6 つのテストが動的に作成されます (テストされる 3 つの値のそれぞれに対して 2 つのテスト)。これは、何かが失敗した場合でも、他のテストが引き続き実行されることを意味します。

require "minitest/autorun"
class MyTests < MiniTest::Unit::TestCase
    ['0', '1111111', '2222222'].each do |phone_number|
        define_method("test_#{phone_number}_has_7_characters") do
            assert_equal(7, phone_number.length)
        end

        define_method("test_#{phone_number}_starts_with_1") do
            assert_equal('1', phone_number[0])
        end
    end
end

適用テスト ケースでは、次の結果が得られます。

# Running tests:

F..F.F

Finished tests in 0.044004s, 136.3512 tests/s, 136.3512 assertions/s.

  1) Failure:
test_0_starts_with_1(MyTests) [stuff.rb:13]:
Expected: "1"
  Actual: "0"

  2) Failure:
test_0_has_7_characters(MyTests) [stuff.rb:9]:
Expected: 7
  Actual: 1

  3) Failure:
test_2222222_starts_with_1(MyTests) [stuff.rb:13]:
Expected: "1"
  Actual: "2"

6 tests, 6 assertions, 3 failures, 0 errors, 0 skips

同じ概念をテストに適用すると、次のことが必要になると思います。

class MyTests < MiniTest::Unit::TestCase
    listOfPhoneNumbersForTesting.each do |phone|
        define_method("test_#{phone}") do
            TestPhone.new phone
        end
    end
end

仕様スタイルのテストを使用する場合、同様のアプローチを取ることができます。

require 'minitest/spec'
require 'minitest/autorun'

describe "my tests" do
  ['0', '1111111', '2222222'].each do |phone_number|
    it "#{phone_number} has 7 characters" do
      assert_equal(7, phone_number.length)
    end

    it "#{phone_number} starts with 1" do
      assert_equal('1', phone_number[0])
    end
  end
end

重要: 注意すべきことの 1 つは、作成したテスト メソッドの名前が各テスト ケースで一意であることを確認する必要があることです。

たとえば、電話番号をメソッド名に含めないと、以前に定義したメソッドが上書きされてしまいます。最終的に、これは最後の電話番号のみがテストされることを意味します。

これは、MiniTest がオンザフライでテスト メソッドを生成し、最終的に最後の .each 変数のみを使用して、既に生成されたテスト メソッドを上書きするためです。

于 2013-09-12T18:27:26.953 に答える