Is there some clean and elegant way to execute my code right after a failed assert in ruby unit tests in Test::Unit
, before teardown
gets executed?
I am doing some automated GUI testing and would like to take a screenshot right after something failed.
If you're on 1.9, don't use Test::Unit::TestCase as your base class. Subclass it and override #run_test to rescue, take the screenshot and reraise:
class MyAbstractTestCase < Test::Unit::TestCase
def run_test( *args )
super(*args)
rescue
snapshot()
raise
end
end
Alternatively, and I think this is actually the most terse way in, you can use a before_teardown hook:
class MyTestCase < Test::Unit::TestCase
add_teardown_hook do |tc|
screenshot() unless tc.passed?
end
end
This won't work on 1.8's test/unit, but will with the minitest in 1.9.
Well you could extend Test::Unit::Assertions
to do what you like, i do not think there is a built-in way to do this. Perhaps something like this (quick & dirty):
require 'test/unit'
module Test::Unit::Assertions
def safe_assert(test, msg=nil)
passed = msg.nil? ? assert(test) : assert(test,msg)
ensure
puts 'take screenshot' unless passed
end
end
class MyTest < Test::Unit::TestCase
def setup
puts 'setup'
end
def teardown
puts 'teardown'
end
def test_something
safe_assert true
puts 'before failing assert'
safe_assert false, "message"
puts 'after failing assert'
end
end
output:
Loaded suite unittest
Started
setup
before failing assert
take screenshot
teardown
F
Finished in 0.001094 seconds.
1) Failure:
test_something(MyTest) [unittest.rb:5]:
message
1 tests, 2 assertions, 1 failures, 0 errors, 0 skips
Test run options: --seed 58428
EDIT: you could actually pass the args to assert
in a simpler way:
module Test::Unit::Assertions
def safe_assert(*args)
passed = assert(*args)
ensure
puts 'take screenshot' unless passed
end
end
also, you could wrap a standard assert
in a begin
-ensure
-end
block if you only need this functionality infrequently:
class MyTest < Test::Unit::TestCase
def test_something
safe_assert true
puts 'before failing assert'
begin
passed = assert false, "message"
ensure
puts 'take screenshot' unless passed
end
puts 'after failing assert'
end
end
or you build a method that ensures a screenshot like in the following example. This actually seems like the cleanest way to me:
def screenshot_on_fail
passed = yield
ensure
puts 'take screenshot' unless passed
end
class MyTest < Test::Unit::TestCase
def test_something_else
screenshot_on_fail do
assert true
end
screenshot_on_fail do
assert false, 'message'
end
end
end
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