I have some unit tests written using Test::Unit::TestCase, with XML generated by ci_reporter. However, due to circumstances beyond my control, they may occasionally fluctuate, and randomly fail. I'd like to detect when a test fails, and attempt to re-run it.
I tried doing this by monkey-patching 'teardown' to check 'passed?', and re-running the tests on a failure. However, the XML output will still show the first failed case, and not the second (now passing) run.
This sounds a bit like the opposite of Multiple tests with minitest
Perhaps this is a possibility: Copy your test case in an own file. As an example, try the following test:
#store it as file 'testcase.rb'
gem 'test-unit'
require 'test/unit'
class X < Test::Unit::TestCase
def test_1
num = rand(10)
assert_true( num < 2, "Value is #{num}")
end
end
Then define your test call in a rake task:
require 'rake'
TEST_REPETION = 10
task :test do
success = false
TEST_REPETION.times{
stdout = `ruby testcase.rb`
if stdout =~ /Failure/
puts "Failure occured - redo the test"
else
puts 'Tests ok'
success = true
exit
end
}
puts "Stopped after #{TEST_REPETION} tries" unless success
end
Now the test is called, until the test succeed or TEST_REPETION are done.
Remarks:
Rake isn't needed, you may do the call without rake (My template was a rake task)
This works only, if your xml changes for each run (it must be regenerated before the test. else you test always the same).
You may store the test result (stdout) in a file and use it later to analyze, which tests failed and try to retest them.
Related
I am trying to write some unit testing for my ruby script. However, it is not working as I think it should work, and with certain tests, it just stops half way through the unit test.
This is the method I am currently testing.
#!/usr/bin/env ruby
require 'ptools'
require 'test/unit'
class InputValidators
# checks whether the input file exist.
def input_file_validator(input_file)
begin
raise ArgumentError, "Error: Input file \"#{input_file}\" does not exist. \n" unless File.exist?(input_file)
raise ArgumentError, "Error: Input file is empty. Please correct this and try again. \n" if File.zero?(input_file)
raise ArgumentError, "Error: Input file is in binary format - only text based input files are supported. \n" if File.binary?(input_file)
rescue Exception => e
puts # a empty line
puts e.message
puts # a empty line
Process.exit(true)
end
end
end
class UnitTests < Test::Unit::TestCase
def test_input_file_validator_1
test_validators = InputValidators.new
assert_equal(nil, test_validators.input_file_validator("./test_inputs/genetic.fna")) #file is present
assert_raise( SystemExit ) {test_validators.input_file_validator("./test_inputs/missing_input.fna")} # file doesn't exist
# assert_equal(nil, test_validators.input_file_validator("./test_inputs/empty_file.fna")) # empty file
# assert_equal(nil, test_validators.input_file_validator("./test_inputs/binary_file.fna")) # a binary file
end
end
Now, if I leave the script as above, the unit test work perfectly...
Current Output:
Run options:
# Running tests:
[1/1] UnitTests#test_input_file_validator_1
Error: Input file "./test_inputs/missing_input.fna" does not exist.
Finished tests in 0.004222s, 236.8797 tests/s, 473.7593 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
ruby -v: ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux]
However, if I even uncomment one of the other asserts, the unit test just stops and doesn't complete.
Output (when uncommenting just one or both of the assertions in the above script):
Run options:
# Running tests:
[1/1] UnitTests#test_input_file_validator_1
Error: Input file "./test_inputs/missing_input.fna" does not exist.
Error: Input file is empty. Please correct this and try again.
I have no idea what I am doing wrong so any help on this would be most appreciated.
Let me know if you need more info.
well, if you run exit and you are not rescuing from that exception, your process just stops running.
i guess that assert_raise does actually capture that error or does some other magic to complete the process. running at_exit hooks might be some of those magic tricks.
despite all this, it's considered a bad practice to use exceptions for workflows. so i would not recommend raising an error and then catching it immediately just to exit the process. i usually just use abort with a message.
I'd like to run my minitest handler tests inside another ruby script (a bootstrapper script of sorts). I'd like to return the results of my tests to a variable that I can then parse to make sure everything passed before moving on. Is this possible? If so, what does the syntax for something like this look like?
You can shell out to run the test and capture the output.
puts "Running foo test:"
output = `ruby -Ilib:test test/test_foo.rb`
puts output
puts "Completed foo test."
Okay so I figured out how to do this using the rake::test library. This code will execute a minitest test, then slurp in the xml from the report and determine if everything passed or not.
require 'rake'
require 'rake/testtask'
require 'ci/reporter/rake/minitest'
require 'xmlsimple'
Rake::TestTask.new do |t|
t.verbose = true
t.test_files = FileList['system_tests/vm_tests.rb']
end
task :test => :"ci:setup:minitest"
Rake::Task[:test].execute
results = XmlSimple.xml_in('test/reports/TEST-VMtests.xml')
if results["failures"] > 0 or results["errors"] > 0
raise "The VM Tests have resulted in failures or errors"
end
We have some tests in our MiniTest::Spec test suite that pass when each test directory is run individually, but fail when the entire suite is run.
Instead of spending hours trying to track down the reason for the failures, I thought it would be easier to just run each test directory in its own TestTask instance, like so:
Dir.new('spec').each do |f|
next if f.start_with? '.'
if File.directory? File.join('spec', f)
Rake::TestTask.new('test') do |t|
t.libs << "app" << "spec"
t.test_files = FileList["spec/#{f}/*_spec.rb"]
t.verbose = true
end
end
end
This causes the tests in each directory to run in "parallel", however. TestTask.new seems to execute each test in a separate thread (though I haven't figured out why yet).
Is there any way to avoid this behavior? I want each directory to run sequentially, since without this I'm running into "stack too deep" errors.
Thanks!
I have an app with some specs written into minitest. As usual, I start them using rake.
Because some times I got a random results, my specs can pass one time, and fail an other time.
In this case, I can keep the sequence number and replay it later, after fixing.
Because I have this kind of tests (with a random result), I generally run rake many time, just to be sure that the app is okay.
I would like to know if there is a nice way to perform multiple rake tests (100 times for example), and stop them if there any failure or any error?
I think you should think again about your test, not about the test call. A test with a random result looks wrong for me.
What's the random factor in your test? Can you write a mock-element for the random factor and repeat the test with different values for the mock-element. So you get a "complete" test.
I created a dummy test with random result to simulate your situation:
#store it as file 'testcase.rb'
gem 'test-unit'
require 'test/unit'
class X < Test::Unit::TestCase
def test_1
num = rand(10)
assert_true( num < 5, "Value is #{num}")
end
end
The following task calls the test 10 times and stops after the first failure:
TEST_REPETION = 10
task :test do
TEST_REPETION.times{
stdout = `ruby testcase.rb`
if stdout =~ /\d+\) Failure/
puts "Failure occured"
puts stdout
exit
else
puts 'Tests ok'
end
}
end
For real usage I would adapt some parts:
Instead puts 'Tests ok' define a counter to see how often the test was succussfull
Instead puts stdoutyou may store the result in a result file?
edit: this problem only happens sometimes
This only appears to happen when I run the test from within TextMate (even when I specify the ruby to run it from by hand with a shebang). If I run it from the terminal then everything is peachy…
Here's some code:
require 'test/unit'
require 'shoulda'
class TestingTest < Test::Unit::TestCase
context "My thing" do
should "always have this test fail, and give me this message" do
assert false
end
end
end
I'm expecting it to tell me something like:
1) Failure:
test: My thing should always have this test fail, and give me this message (TestingTest)
# etc
An assert message, if one was given
But I'm getting:
1) Failure:
test:8
Failed assertion, no message given.
So what am I missing? The example code above is as simple as I think I can make it and I can't see the problem!
try inheriting from ActiveSupport::TestCase instead of the Test::Unit::TestCase