Page 2 of 2
Re: Testing Class Hierarchy
Posted: Thu Feb 05, 2009 3:55 am
by Chris Corbyn
mickeyunderscore wrote:Chris Corbyn wrote:This we disagree on. By subclassing a class you are not testing the same class anymore. Like I say, you've effectively changed the behaviour of the superclass. You're making some very big assumptions that the subclass does not break the superclass behaviour and I think that is dangerous. I'm happy to remain in disagreement though...
I'm not sure I follow this, would you retest all methods? Or just ones that have been extended/overridden, or involve the use of extended/overridden methods?
I wouldn't manually write the test coverage to re-test all methods no. I just subclass the original test case. How do you know which methods involve the use of the overridden methods?
Re: Testing Class Hierarchy
Posted: Thu Feb 05, 2009 4:38 am
by mickeyunderscore
I see, I've not had much experience writing test cases, but that seems to make sense now. I thought you meant you manually rewrote all of the tests!
Re: Testing Class Hierarchy
Posted: Thu Feb 05, 2009 5:02 am
by Jenk
Chris Corbyn wrote:Jenk wrote:Same applies for sub/super classes. You are not developing the super class when you are developing the subclass, so why are you testing the superclass? The superclass has it's own test, no need to duplicate.
This we disagree on. By subclassing a class you are not testing the same class anymore. Like I say, you've effectively changed the behaviour of the superclass. You're making some very big assumptions that the subclass does not break the superclass behaviour and I think that is dangerous. I'm happy to remain in disagreement though...
You haven't changed the superclass behaviour at all. Just because you have subclassed ClassA with ClassB does not mean the next time you instantiate with 'new ClassA();' that you'll get differing behaviour, unless I have misunderstood your post. And your point of "By subclassing a class you are not testing the same class anymore." that is *exactly* correct, but your superclass is still it's own class (abstract, maybe but that's a different kettle of fish).
If the behaviour you have developed into ClassB is overriding something in ClassA, then test it. Otherwise you quite literally are duplicating your tests.
What I'd consider a valid test to "duplicate" (but it's not actually duplication because it is different behaviour!) is something like the Shapes example:
Code: Select all
class Shape {
private __numberOfSides = 0;
public function getNumberOfSides() {
return $this->__numberOfSides;
}
public function setNumberOfSides($num) {
$this->__numberOfSides = $num;
}
}
class Triangle extends Shape {
public function __construct () {
$this->setNumberOfSides(3);
}
}
// etc for other shapes
It would be perfectly valid for each subclass to assert/expect on getNumberOfSides() because the return value (and behaviour) is different for each subclass.
But for something as arbitrary (and unlikely, I admit) as the following:
Code: Select all
class Foo {
public function getSomething() {
return "something";
}
}
class Bar extends Foo {
public function getSomethingElseToo() {
return $this->getSomething() + "ElseToo";
}
}
I would not test getSomething() for every subclass of Foo.. it is just unwarrented because the behaviour of getSomething() has not altered.
And to say "how can you be sure it doesn't affect it [without breaking encapsulation]" well, you can say that about anything, if we were to take it to the extreme. Time of day, the weather, have you paid your electricity bill in time, etc.
And just also to add, Encapsulation rules are lax when you are subclassing (and is also a strong argument against Inheritance, for the very same reason as this topic!) because you are actually looking at the code and developing, not manipulating an object via its interface.
Re: Testing Class Hierarchy
Posted: Thu Feb 05, 2009 5:13 am
by Chris Corbyn
Taking your Shape example, if the Shape class had a method not only to return the number of sides, but also to return its area, and getArea() just so happened to use getNumberOfSides(), you would not know that you'd just broken that method if all you cared about was that it had a different number of sides.
These such rudimentary examples are never convincing, and the shape/area one falls down when you start to break it apart, but nontheless it puts across the sort of thing I'm talking about. A class can use its public methods as part of its implementation just as much as it can use its private methods.
With regards to saying that by subclassing you change the behaviour of the superclass, I was taken out of context. What I mean is that the subclass does not have the same behaviour as the superclass... by changing one method you may change a massive amount of behaviour inadvertently due to the superclass making use of that method you just overrode (like the Shape).
Re: Testing Class Hierarchy
Posted: Thu Feb 05, 2009 5:28 am
by Jenk
Well to answer the getArea() no, you'd expect differing results for each Shape, and you'd assert the resultant value - but you wouldn't need know about it's internal use of getNumberOfSides().
You're point is that because of encapsulation, your subclass could be broken, but your answer to it is to assert behaviour for a superclass on it's subclass, when you've already broken encapsulation merely by subclassing anyway.. because in order to subclass, you have to know of the implementation of the superclass.
Rudimentary examples are used simply because real-world examples are few-and-far and will detract from the actual conversation (by means of trying to understand the example etc) but theory is still the same.
Re: Testing Class Hierarchy
Posted: Thu Feb 05, 2009 5:57 am
by Chris Corbyn
Jenk wrote:You're point is that because of encapsulation, your subclass could be broken, but your answer to it is to assert behaviour for a superclass on it's subclass, when you've already broken encapsulation merely by subclassing anyway.. because in order to subclass, you have to know of the implementation of the superclass.
Just like most things that you test, you generally know how it all works at the time you write it. But one point of test automation is so that as code evolves you are able to quickly detect regressions. This is what you're missing by avoiding testing your subclass's remaining methods. The superclass test case may continue to pass as implementation evolves, but the subclass may break as a result of your override.
I know because I've been through the process where my subclass has actually broken some intended behaviour. Overriding methods is a fairly significant change. josh also points out that by structuring his tests in this way he found bugs he was not aware of.
I have still yet to hear a counter argument as to why the extra test coverage is bad. And yes, I'm fully aware of the concerns with test duplication but I don't consider SUT-A and SUT-B to be the same if SUT-B is a subclass of SUT-A. I think this is where we differ. You think that all methods in SUT-A will still work no matter what you override in SUT-B... I don't make that assumption.
Re: Testing Class Hierarchy
Posted: Thu Feb 05, 2009 3:47 pm
by josh
Jenk, all hes saying is its possible for us mortals to override a method we didn't intend to override. I for one would prefer to have a test go off if I break superclass behavior, but on the other hand you prefer to not use visibility, so obviously our preferences on "safety" vastly differ.
Here's an example. Say there's a template method a model is supposed to use but you forgot and you use the constructor. In some instances only retesting the subclass would show you that something is inconsistent with that object's state.
Re: Testing Class Hierarchy
Posted: Fri Feb 06, 2009 5:58 am
by Jenk
That's a fair point, and certainly clarifies it (to me at least)