I’d like to chain setup in a unit test, so that it calls a method in a
module BEFORE running through the setup code. I’d like to do it without
having to put super() in the test’s setup method.
module MyModule
module InstanceMethods
def setup
puts ‘module setup’
end
end
def self.included(base)
base.send :include, InstanceMethods
end
end
class MyUnitTest < Test::Unit::TestCase
include MyModule
def setup
puts ‘class setup’
end
end
If this were working when I run a test in MyUnitTest it should print out
module setup
class setup
Unfortunately I can’t get it to work. Even with alias_method, I run
into problems it seems because the class setup is defined after the
module is included. Anyone one have any ideas?
On Thu, Dec 10, 2009 at 01:33:58PM +0900, Raymond O’Connor wrote:
I’d like to chain setup in a unit test, so that it calls a method in a
module BEFORE running through the setup code. I’d like to do it without
having to put super() in the test’s setup method.
What’s wrong with super()? We use it in all of our other objects.
Tests are normal objects too.
On Thu, Dec 10, 2009 at 01:33:58PM +0900, Raymond O’Connor wrote:
I’d like to chain setup in a unit test, so that it calls a method in a
module BEFORE running through the setup code. I’d like to do it without
having to put super() in the test’s setup method.
What’s wrong with super()? We use it in all of our other objects.
Tests are normal objects too.
Trying to keep things as encapsulated as possible. Just seems wrong
that people including the module need to know to call super in setup
before their own setup code.
before their own setup code.
That’s the normal way to do business with super classes - and included
modules. If you look at MyUnitTest.ancestors you will see that the
class is first in the chain and then the included module appears.
That’s why #setup of your class is always invoked before #setup in any
included module.
Another solution to what you want to do would be this: use the template
method pattern.
module InstanceMethods
def setup
puts ‘module setup’
setup_local
end
def setup_local
raise “Sub class needs to implement this!”
end
end
class MyUnitTest < Test::Unit::TestCase
include InstanceMethods
def setup_local
puts ‘class setup’
end
end
Although you can still break the pattern by defining #setup in the class
because Ruby does not have final methods (e.g. like Java).
Raymond, why do you use two modules here? As far as I can see there is
no use case for a second module. Also, you could make InstanceMethods a
regular class which inherits Test::Unit::TestCase. Placing this in a
module only pays off if you want to include the module in classes which
need to have differing super classes.
A completely alternative way would be to define a mini DSL where you
have full control over what happens:
untested
def test(&b)
Class.new do
def setup
puts ‘module setup’
super
end
end.send(:include, Module.new(&b))
end
MyUnitTest = test do
def setup
puts ‘class setup’
end
end
Kind regards
robert
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.