I am new to Java testing with JUnit. I have to work with Java and I would like to use unit tests.
My problem is: I have an abstract class with some abstract methods.
You could do something like this
public abstract MyAbstractClass {
@Autowire
private MyMock myMock;
protected String sayHello() {
return myMock.getHello() + ", " + getName();
}
public abstract String getName();
}
// this is your JUnit test
public class MyAbstractClassTest extends MyAbstractClass {
@Mock
private MyMock myMock;
@InjectMocks
private MyAbstractClass thiz = this;
private String myName = null;
@Override
public String getName() {
return myName;
}
@Test
public void testSayHello() {
myName = "Johnny"
when(myMock.getHello()).thenReturn("Hello");
String result = sayHello();
assertEquals("Hello, Johnny", result);
}
}
As an option, you can create abstract test class covering logic inside abstract class and extend it for each subclass test. So that in this way you can ensure this logic will be tested for each child separately.
With the example class you posted it doesn't seem to make much sense to test getFuel()
and getSpeed()
since they can only return 0 (there are no setters).
However, assuming that this was just a simplified example for illustrative purposes, and that you have legitimate reasons to test methods in the abstract base class (others have already pointed out the implications), you could setup your test code so that it creates an anonymous subclass of the base class that just provides dummy (no-op) implementations for the abstract methods.
For example, in your TestCase
you could do this:
c = new Car() {
void drive() { };
};
Then test the rest of the methods, e.g.:
public class CarTest extends TestCase
{
private Car c;
public void setUp()
{
c = new Car() {
void drive() { };
};
}
public void testGetFuel()
{
assertEquals(c.getFuel(), 0);
}
[...]
}
(This example is based on JUnit3 syntax. For JUnit4, the code would be slightly different, but the idea is the same.)
Create a concrete class that inherits the abstract class and then test the functions the concrete class inherits from the abstract class.
You can not test whole abstract class. In this case you have abstract methods, this mean that they should be implemented by class that extend given abstract class.
In that class programmer have to write the source code that is dedicated for logic of his.
In other words there is no sens of testing abstract class because you are not able to check the final behavior of it.
If you have major functionality not related to abstract methods in some abstract class, just create another class where the abstract method will throw some exception.
You can instantiate an anonymous class and then test that class.
public class ClassUnderTest_Test {
private ClassUnderTest classUnderTest;
private MyDependencyService myDependencyService;
@Before
public void setUp() throws Exception {
this.myDependencyService = new MyDependencyService();
this.classUnderTest = getInstance();
}
private ClassUnderTest getInstance() {
return new ClassUnderTest() {
private ClassUnderTest init(
MyDependencyService myDependencyService
) {
this.myDependencyService = myDependencyService;
return this;
}
@Override
protected void myMethodToTest() {
return super.myMethodToTest();
}
}.init(myDependencyService);
}
}
Keep in mind that the visibility must be protected
for the property myDependencyService
of the abstract class ClassUnderTest
.
You can also combine this approach neatly with Mockito. See here.