abstract class BaseClass{
private final Dependency dep;
BaseClass(final Dependency dep){
this.dep = dep;
}
abstract void toBeImplementedBySubclasses();
public int concreteMethod(){
//Do some processing
return any_integer;
}
}
class DerivedOne{
@Inject
DerivedOne(final Dependency dep){
super(dep);
}
public void toBeImplementedBySubclasses(){
//DO SOMETHING RELEVANT TO DERIVED ONE IMPLEMENTATION
}
}
class DerivedTwo{
@Inject
DerivedOne(final Dependency dep){
super(dep);
}
public void toBeImplementedBySubclasses(){
//DO SOMETHING RELEVANT TO DERIVED TWO IMPLEMENTATION
}
}
I want to test concrete methods in abstract class. Is it ok if I test the concrete methods in base class in the unit test for any of the two derived classes, or is there any other way?
So, if write test for DerivedOne class, it will include test for all methods AND the concrete method of the base class as well. I know there is a thing "Mockito.CALLS_REAL_METHODS", using which we can test abstract classes, but in my case my base class has some dependencies which I initalise/inject using super() insider constructor of my derived classes, so I cant be doing it using CALLS_REALS_METHODS
There are two options which immediately come to mind here.
Firstly, you could write an abstract test class, which handles testing these methods, and then the test classes for your concrete implementations do the rest. For example:
public abstract class YourAbstractClassTest {
protected abstract YourAbstractClass getInstance();
@Test
public void testThing() {
final YourAbstractClass instance = this.getInstance();
instance.callMethod();
Assertions.assertTrue(instance.someProperties());
}
}
Alongside:
public class ConcreteSubclassTest extends YourAbstractClassTest {
private final ConcreteSubclass instance = new ConcreteSubclass();
@Override
protected YourAbstractClass getInstance() {
return this.instance;
}
@Test
public void moreTesting() {
this.instance.implementationSpecificMethod();
}
}
You could also create a dummy subclass in a test class for it:
public class AbstractClassTest {
private final AbstractClass instance = new AbstractClass() {
@Override
public void abstractMethod() {
throw new UnsupportedOperationException();
}
}
@Test
public void testThing() {
this.instance.concreteMethod();
// Just make sure this doesn't ever go near the
// methods you dummied up above...
}
}