Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing Unit Tests for inherited classes in Java

Consider the following simple class hierarchy in Java

class Foo {
    protected void someMethod(Bar bar) {
        ...
    }

    protected void someOtherMethod(Baz baz) {
        ...
    }
}

class EnhancedFoo extends Foo {
    @Override
    protected void someMethod(Bar bar) {
        ...
    }
}

I now start writing JUnit unit tests for these two classes. Since the contracts for the method someMethod are same for both the classes, I need basically exactly the same test methods (concerning the someMethod method) for both the classes, which leads to code duplication. Doing this for a much richer class hierarchy with multiple overwritten methods, it just feels like inheritance is bad for testability.

Also, even though the method someOtherMethod is not overridden in ExtendedFoo, I need to include the pertaining tests for ExtendedFoo because that is still the contract and this extended class and unit tests should test this.

Is there some other way of organizing hierarchies in Java that is better for testability? Is there some JUnit construct that would help alleviate this problem?

like image 279
ironstein Avatar asked Oct 24 '18 06:10

ironstein


People also ask

How do you unit test a class that extends a base class?

If you really need to extend the base class to override something, extract the functionality to a third class and make the extended class a proxy. The extended class does nothing else than call methods on the third class. E.g. This way, you can test the real implementation, without instantiating the base class.

Can we write unit tests for abstract class?

Unit testing abstract classes leads to the same consequences as unit testing private methods. In fact, these two practices are essentially the same anti-pattern. Both couple your tests to implementation details and therefore increase the noise you have to deal with after each refactoring.

What is test inheritance?

Inheritance definitionInheritance in OOP is achieved when one object acquires (inherits) the properties and the behaviors of the parent object. This means that the protected and public members of the parent class can be reused in the derived class, without having to define them all over again.


1 Answers

One approach we used when we had a very similar scenario was to also reuse the est classes:

class FooTest {
    @Test
    public void testSomeMethodBar() {
        ...
    }

    @Test
    public void void someOtherMethodBaz(Baz baz) {
        ...
    }
}

And extend it for subclass tests:

class EnhancedFooTest extends FooTest {
    @Test
    public void testSomeMethodBar() {
        ...
    }
}

JUnit will run this specific overridden test method, and also the other default tests in FooTest. And that eliminates unnecessary duplication.

Where appropriate, some test classes are even declared abstract, and are extended by concrete test classes (tests for concrete classes).

like image 172
ernest_k Avatar answered Oct 05 '22 02:10

ernest_k