Используя Ruby и Minitest, как запустить один и тот же testcase с разными данными, управляемыми только списком

У меня есть код Ruby 2.0, который работает на телефонных номерах, которые я хочу проверить с помощью MiniTest. У меня есть функция, которая принимает аргументы номера телефона и проверяет его (включая утверждения). Каждый раз, когда я вызываю эту функцию, я хочу, чтобы это был новый тестовый случай. Что-то вроде этого:--4-->

listOfPhoneNumbersForTesting.each { |phone|   testphone phone }  

чего я не хочу, так это:

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

... повторяется 10, 20 или 100 раз, чтобы проверить каждый номер телефона ...

очевидно, я мог бы поместить код цикла в a MiniTest:: Unit:: TestCase, но это приводит только к одному testcase независимо от того, сколько телефонных номеров я тестирую, и мне это не нравится. (Кроме того, если один из утверждений терпит неудачу, то больше не проверяются номера телефонов, и я этого не хочу!) Также вторая форма выглядит как нарушение DRY для меня, так как имя класса, имя функции и аргумент содержат номер телефона.

как-то я чувствую, что я должен быть в состоянии иметь один класс под названием TestPhone и создать его с номером телефона аргумент, и получить это в MiniTest framework. но я бы хотел использовать setup (), Fixtures, metaprogramming или что-нибудь еще, если это сработает.

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

где TestPhone является подклассом TestCase и заканчивается вызовом testphone для выполнения работы.

В основном, то, что я хочу, это: 1. Один список телефонных номеров, и если я добавляю номер в список, я получаю еще один тестовый случай в отчете. 2. Если не удается выполнить тесты, связанные с одним номером телефона, остальные еще проверяются. 3. Все телефонные номера проходят одинаковое тестирование, которое включает в себя несколько утверждений.

спасибо!

1 ответов


вы можете динамически определять методы.

в следующем примере динамически создаются 6 тестов (по 2 теста для каждого из 3 тестируемых значений). Это означает, что если что-то не удается, другие тесты все еще выполняются.

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

тестовый пример apply дает следующие результаты:

# 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

аналогичный подход можно использовать при использовании spec-style тесты:

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

важно: следует отметить, что вам нужно убедиться, что имя созданных методов тестирования уникально для каждого тестового случая.

например, если вы не помещаете номер телефона в имя метода, вы в конечном итоге перезаписываете свои ранее определенные методы. В конечном счете это означает, что тестируется только последний номер телефона.

это потому, что MiniTest генерирует методы тестирования на лету и уже перезаписывает сгенерированные методы тестирования, в конечном счете, только с использованием последнего .каждая переменная.