I have Ruby 2.0 code that operates on phone numbers, which I want to test using MiniTest. I have a function which takes a phone number arguments and tests it (including asserts). Each time I call that function, I want it to be a new test case. Something like this:
listOfPhoneNumbersForTesting.each { |phone| testphone phone }
What I DO NOT want is this:
class test2125551212 < MiniTest::Unit::TestCase def t2125551212 testphone "2125551212" end end
... repeated 10, 20, or 100 times to test each phone number ...
Obviously, I could put the loop code within a MiniTest::Unit::TestCase, but that results in just one testcase no matter how many phone numbers I test, and I don't like that. (Also, if one of the asserts fail, then no more phone numbers are tested, and I don't want that!) Also the second form looks like a violation of DRY to me, since the class name, function name, and argument all contain the phone number.
Somehow I feel that I should be able to have one class called TestPhone, and create it with the phone number argument, and get that into the MiniTest framework. but I would be willing to use setup(), Fixtures, metaprogramming, or just about anything else, if it would work.
listOfPhoneNumbersForTesting.each { |phone| TestPhone.new phone }
Where TestPhone is a TestCase subclass, and ends up calling testphone to do the work.
Basically, what I want is this: 1. One list of phone numbers, and if I add a number to the list, I get one more TestCase in reporting output. 2. If the tests associated with one phone number fail, the rest are still tested. 3. All phone numbers get the same testing, which includes several assertions.
Thanks very much!
We can run all of our tests at once by using the bin/rails test command. Or we can run a single test file by passing the bin/rails test command the filename containing the test cases. This will run all test methods from the test case.
To run a Minitest test, the only setup you really need is to require the autorun file at the beginning of a test file: require 'minitest/autorun' . This is good if you'd like to keep the code small. A better way to get started with Minitest is to have Bundler create a template project for you.
Integration. Don't try to test all the combinations in integration tests. That's what unit tests are for. Just test happy-paths or most common cases.
You could dynamically define the methods.
In the following example, 6 tests are dynamically created (2 tests for each of the 3 values being tested). This means that if anything fails, the other tests still run.
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
The apply test case gives the following results:
# 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
Applying the same concept to your tests, I think you want:
class MyTests < MiniTest::Unit::TestCase listOfPhoneNumbersForTesting.each do |phone| define_method("test_#{phone}") do TestPhone.new phone end end end
A similar approach can be taken when using the spec-style tests:
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
IMPORTANT: One thing to note is that you need to make sure that the name of the test methods created are unique for each test case.
For example, if you do not put the phone number in the method name, you end up overwriting your previously defined methods. Ultimately this means that only the last phone number gets tested.
This is because MiniTest generates the test methods on the fly and will overwrite already generated test methods, ultimately only using the last .each variable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With