Chain Method in Class with Method in Module

R

Raymond O'Connor

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?

Thanks!
 
A

Aaron Patterson

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. :)
 
R

Raymond O'Connor

Aaron said:
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.
 
R

Robert Klemme

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.

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top