Reusing base classes tests?

Hi,

Whats the standard way to reuse the Test::Unit tests for a
base class when deriving a subclass? Should the testcase
class derive from the base class testcase class or are there
better ways?

Regards,

Karsten

···


http://fastmail.fm/ - IMAP accessible web-mail

Hi Karsten,

I’m not sure what you would need to retest in the subclass since whatever you
tested in the superclass has also been tested in the subclass. I tend to only
test the public interfaces. In my experience tests are not reused, but can
have parts of them extracted and reused, the test itself (the inputs and
assertions) are specific for that individual method - if they are not, do you
have the same method twice or is your design as simple as it ought to be?
Perhaps I don’t understand your example enough, can you provide a scenario?


Signed,
Holden Glova

···

On Thu, 03 Oct 2002 21:58, coma_killen@fastmail.fm wrote:

Hi,

Whats the standard way to reuse the Test::Unit tests for a
base class when deriving a subclass? Should the testcase
class derive from the base class testcase class or are there
better ways?

Regards,

Karsten

coma_killen@fastmail.fm wrote:

Whats the standard way to reuse the Test::Unit tests for a
base class when deriving a subclass? Should the testcase
class derive from the base class testcase class or are there
better ways?

The best way I have found is to inherit, then create the testee in a method
called ‘warmUp’. Then override that method. Don’t call ‘warmUp’ from
‘initialize’.

This page does not contain enough:

    http://c2.com/cgi/wiki?AbstractTest

Test rigs are pragmatic, not magic. Put another way, Liskov Substitution
Principle applies between the base and derived test, so the system should

not< be able to tell the difference between a test method that calls
‘warmUp’ and one that does not. LSP in the tests does not mean everyone
must call ‘warmUp’.

Classes, however, should follow LSP, so tests a base class should pass the
derived class should pass too.

Put them together, and some test methods should not call ‘warmUp’.
Pragmatically, they test support aspects of the tested class. LSP does not
apply.

So the complete answer: Inherit, but don’t override ‘initialize’. Override,
instead, ‘warmUp’, and call this at the top of each method. In the base
test class, ‘warmUp’ returns a base class instance, and in a derived class
it returns a derived class instance.

‘warmUp’ should assign the testee to a member variable (for convenience),
and the ‘tearDown’ method may care to destroy or un-do this testee.

(This happens to be Robert C. Martin’s “Stairway to Heaven Design Pattern”,
but with different LSP ramifications.)

···


Phlip
greencheese.org
– Set phasers on illin’ –

I think I lost you here. Assume the following

class Vehicle
end

class Car
def wheels
return 4
end
end

class Truck
def wheels
return 8
end
end

class CarTest
def test_wheels
assert_equal(4,testee.wheels)
end
end

How should Truck pass CarTest? Or should TruckTest inherite from CarTest
and override test_wheels? Whould this be according to LSP?

-billy.

···

On Fri, Oct 04, 2002 at 01:26:01AM +0900, Phlip wrote:

coma_killen@fastmail.fm wrote:

Whats the standard way to reuse the Test::Unit tests for a
base class when deriving a subclass? Should the testcase
class derive from the base class testcase class or are there
better ways?

The best way I have found is to inherit, then create the testee in a method
called ‘warmUp’. Then override that method. Don’t call ‘warmUp’ from
‘initialize’.

This page does not contain enough:

    http://c2.com/cgi/wiki?AbstractTest

Test rigs are pragmatic, not magic. Put another way, Liskov Substitution
Principle applies between the base and derived test, so the system should

not< be able to tell the difference between a test method that calls
‘warmUp’ and one that does not. LSP in the tests does not mean everyone
must call ‘warmUp’.

Classes, however, should follow LSP, so tests a base class should pass the
derived class should pass too.


Meisterbohne Söflinger Straße 100 Tel: +49-731-399 499-0
eLösungen 89077 Ulm Fax: +49-731-399 499-9

Classes, however, should follow LSP, so tests a base class should pass
the derived class should pass too.

Philipp Meier wrote:

How should Truck pass CarTest? Or should TruckTest inherite from CarTest
and override test_wheels? Would this be according to LSP?

LSP means the caller (in this case the test engine) can’t tell we called
one test or another. That’s fine because tests should not push side-effects
into the engine.

LSP in the tested classes means they should not surprise their callers. Not
that they always have the same wheel count. For the above situation…

class Car
def wheels
return 4
end
end

class Truck
def wheels
return 8
end
end

class VehicleTest
def test_wheels
testee = warmUp()
assert_equal ( myWheelCount(), testee.wheels() )
end
end

class CarTest < VehicleTest
def warmUp()
@testee = Car.new()
return @testee
end

    def myWheelCount
            return 4
    end

end

class TruckTest < VehicleTest
def warmUp()
@testee = Truck.new()
return @testee
end

    def myWheelCount
            return 8
    end

end

Now push CarTest and TruckTest, but not VehicleTest, into the test suite.

Thanks for helping me create a concrete example.

···


Phlip
greencheese.org
– All sensors report Patti having a very good time –

Ok, now I unterstood. Keeping the Car metaphor LSP meens e.g. that the
method “turn_key_to_off_position” should not e.g. turn off the lights in
the car class but do so in the truck class!? (Consider turning of the
lights as a possible side-effect.)

-billy.

···

On Fri, Oct 04, 2002 at 02:06:06AM +0900, Phlip wrote:

Classes, however, should follow LSP, so tests a base class should pass
the derived class should pass too.

Philipp Meier wrote:

How should Truck pass CarTest? Or should TruckTest inherite from CarTest
and override test_wheels? Would this be according to LSP?

LSP means the caller (in this case the test engine) can’t tell we called
one test or another. That’s fine because tests should not push side-effects
into the engine.


Meisterbohne Söflinger Straße 100 Tel: +49-731-399 499-0
eLösungen 89077 Ulm Fax: +49-731-399 499-9

Another way, but with less code:

def assert_wheels_equal expected, klass
assert_equal expected, klass.new.wheels
end

class CarTest
def test_wheels
assert_wheels_equal 4, Car
end
end

class TruckTest
def test_wheels
assert_wheels_equal 8, Truck
end
end

Maybe I’m just being thrown by the simplicity of the example.
Are there more complex cases that justify the extra base class?

I suppose that this version doesn’t “force” subclasses to make
the assertion.

Another way to phase the Phlip version is just:

class VehicleTest
def test_wheels
assert_equal myWheelCount, classUnderTest.new.wheels
end
end

class CarTest < VehicleTest
def classUnderTest
Car
end
def myWheelCount
4
end
end

class TruckTest < VehicleTest
def classUnderTest
Truck
end
def myWheelCount
8
end
end

  • Ryan King
···

On 2002.10.04, Phlip phlip_cpp@yahoo.com wrote:

class VehicleTest
def test_wheels
testee = warmUp()
assert_equal ( myWheelCount(), testee.wheels() )
end
end

class CarTest < VehicleTest
def warmUp()
@testee = Car.new()
return @testee
end

    def myWheelCount
            return 4
    end

end

class TruckTest < VehicleTest
def warmUp()
@testee = Truck.new()
return @testee
end

    def myWheelCount
            return 8
    end

end