My Watir tests for a particular application are grouped into three subclasses of Test::Unit::TestCase. To run them all I have a top-level test suite that looks like this:
require 'test/unit' server.start require 'test/first_tester' require 'test/second_tester' require 'test/third_tester' server.stop
But this doesn’t work as intended, because the server.stop
line at the end of the script is executed before the test suite is constructed and executed, which is obviously not what I want. The problem is in test/unit
: the require
causes this script to collect every test method in the ObjectSpace
and then invoke the runner on the resulting suite.
What I would like is to have setup
and teardown
methods on TestSuite
; but they aren’t there. I feel sure someone somewhere must have done this already (the closest I could find was this old post on ruby-talk), but I couldn’t find one quickly so I wrote my own:
require 'test/unit/testsuite' require 'test/unit/ui/console/testrunner' require 'test/first_tester' require 'test/second_tester' require 'test/third_tester' class TS_MyTestSuite < Test::Unit::TestSuite def self.suite result = self.new(self.class.name) result << FirstTester.suite result << SecondTester.suite result << ThirdTester.suite return result end def setup server.start end def teardown server.stop end def run(*args) setup super teardown end end Test::Unit::UI::Console::TestRunner.run(TS_MyTestSuite)
Please let me know if this solution – or anything equivalent – is already published elsewhere, because I hate re-inventing wheels…
Try this:
at_exit {p ‘server.stop’}
require ‘test/unit’
p ‘server.start’
require ‘a_test’
I’ve used this several times. Because of the way that test/unit runs test cases (in an at_exit) and how at_exits get unrolled this works
-andy
Nice job.
With this you can avoid fixtures, and place database population in your setup and database clear out in your teardown.
This saves me a headache, as I’ve got a complex schema with all sorts of proper data modelling in it, which makes fixtures impossible.
I also didn’t like the overhead of setup and teardown of data for EVERY unit test in a test file, its not DRY at all going down that route.
Hal fulton has a book titled “The Ruby Way” and he has a snippet of code to solve this problem. The method described above may work if you are running rails tests, but some people (like myself) are testing things completely unrelated to rails. Basically it works like this:
In your Test
class << self
def startup
puts ‘this will be run only once and before any test runs’
end
def shutdown
puts ‘this will be run at the end of the tests’
end
def suite
mysuite = super
def mysuite.run(*args)
RegistrationTest.startup()
super
RegistrationTest.shutdown()
end
mysuite
end
end
The example given in the book is slightly different. I used the methods startup and shutdown instead of the ones he gave because in the next version of ruby test::unit they will have this support built in (and then you can remove the suite method override that we have).
Oops, I left the name of my class in the previous post so it probably didnt make sense.
Let me give you a more concrete example so its not confusing:
class MyTest < Test::Unit::TestCase
class << self
def startup
puts ‘run before any tests have started’
end
def shutdown
puts ‘run after all tests have finished’
end
def suite
mysuite = super
def mysuite.run(*args)
MyTest.startup()
super
MyTest.shutdown()
end
mysuite
end
end
def setup
puts ‘run before each test’
end
def teardown
puts ‘run after each test’
end
end
I am using the Aptana Studio for writing ruby.
I see the following methods in : Test::Unit::TestCase base class –
# Called before every test method runs. Can be used
# to set up fixture information.
def setup
end
# Called after every test method runs. Can be used to tear
# down fixture information.
def teardown
end
Filling up these two methods worked like a charm!.
#setup and #teardown are called around every test method. What we’re looking for here is something that will be called once at the start of testing and once at the end.
Did you ever come to any other conclusions as to finding the best way to execute a non-stop test suite in Ruby? I’m using Ruby (Test::Unit) and Selenium to execute automated tests but the browser session closes after each test which is not desirable. I’d like to find a way to have the setup method called only once at the beginning, then have each test run back to back followed by the teardown method.
I’m not totally clear as to how I can use the example you gave in a selenese kind of way. Any advice would be greatly appreciated!
@Chris, I gave up on Test::Unit several years ago, and now I use Cucumber and RSpec. So I haven’t revisited this problem, because I solve my needs in a totally different way.
I’m curious though — why do you find it undesirable to close the browser between tests?
Well, it may be due to the fact that I’m new to the field and haven’t found a more optimal way to run (and write) my tests. Since I’m mainly dealing with automated testing right now, I’ve broken long processes down into smaller tests. When trying to run each test as part of a suite, I run into a problem when the browser session closes because the user gets logged out. So, either I could add steps to login the user again at the beginning of each test, or I could just run one very long test, which I don’t think is best practice (but as I said, I’m pretty green so maybe that would be best!). I really like Selenium due to its ease of use and it’s worth mentioning that I can indeed run individual tests as part of a suite in the IDE without having this problem, but I need something a bit more robust.
I’ve been enjoying your writings by the way…thanks!
@Chris, I do two things to alleviate that problem. First, my end-to-end tests each login separately at the start of the test; it adds a few microseconds to the test, but it gives me a clean slate for the scenario and allows more flexibility. Second. I write as much code as possible in domain objects that are independent of the user/session context; these objects (the “middle hexagon”) can be unit tested independently, and give a lot of confidence about whether the end-to-end tests will work. See https://silkandspinach.net/2005/03/22/the-middle-hexagon-should-be-independent-of-the-adapters/ and http://www.growing-object-oriented-software.com/ for a lot more on this.