http://stackoverflow.com/questions/6645263/unit-testing-overridden-methods-which-call-super (This question has similar wording but is not the same)
I have something along the lines of:
public class SuperClass {
private int superClassInteger = 2;
public void superClassMethod() {
superClassInteger = 5;
}
public int getSuperClassInteger() {
return superClassInteger();
}
}
Then in my test I have:
public class SuperClassTest {
public void testSuperClassMethod() {
SuperClass superClass = new SuperClass();
superClass.superClassMethod();
assertEquals(5, super.getSuperClassInteger())
}
}
I then have a subclass:
public class SubClass {
private int subClassInteger = 2;
public void subClassMethod() {
super.superClassMethod();
subClassInteger = 32;
}
public int getSuperClassInteger() {
subClassInteger;
}
}
Then my test for the subclass:
public class SubClassTest {
public void testSubClassMethod() {
SubClass subClass = new SubClass();
subClass.subClassMethod();
assertEquals(5, subclass.getSuperClassInteger());
assertEquals(32, subclass.getSubClassInteger())
}
}
My problem is that to test the behavior of the subclass, I am repeating the test code I have for the super class. I could take out: assertEquals(5, subclass.getSuperClassInteger());
as I just want to test the business logic of the subclass. However, the problem with this is that if somebody accidentally removes the call to superClassMethod
the test will still pass. So I need verify that a call to super is made. What is a common way of testing this use case?
Note: I know composition / strategy pattern vs inheritance helps solve this problem but for that to be the solution you are basically saying that I should NEVER override a method and invoke super in my code (which I find hard to believe there will never be a use for)
Use mockito spies. You can check for nearly any method call using that testing Framework.
https://github.com/mockito/mockito
This is probably not the answer you want (i.e not a workaround), but the answer you deserve but you should never override a method and invoke super.
I'm working on a legacy project that does that a lot, it's a nightmare to maintain, to debug and to test.
Instead, it's better to use an abstract class with a template method pattern:
public class SuperClass<T> {
public void include(T t) {
validate(T);
dao.save(T);
}
// I've found code like that.
public void validate(T t) {
}
}
public class SubClass1 extends SuperClass<MyClass> {
@Override
public void include(MyClass mc) {
doStuff(mc);
doMoreStuff(mc);
super.include(mc);
}
@Override
public void validate(MyClass mc) {
doValidationStuff();
}
}
public class SubClass2 extends SuperClass<AnotherClass> {
@Override
public void include(AnotherClass ac) {
doDifferentStuff();
super.include(mc);
}
}
public abstract class AbstractClass<T> {
abstract void validate(T t);
// this method can now be tested
public void include(T t) {
validate(T);
dao.save(T);
}
}
public class Class1 extends AbstractClass<MyClass> {
public void validate(MyClass mc) {
doValidationStuff();
doStuff(mc);
doMoreStuff(mc);
}
}
public class Class2 extends AbstractClass<AnotherClass> {
public void validate(AnotherClass ac) {
doDifferentStuff();
}
}
As you can see, this refactoring simplifies maintenance and testing, you don't have to worry about having to mock the superclass method call in the Class1 and Class2 tests, and the code is closed to modification and open to extension, i.e, more maintainable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With