Используя 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 генерирует методы тестирования на лету и уже перезаписывает сгенерированные методы тестирования, в конечном счете, только с использованием последнего .каждая переменная.