Reputation: 808
I am trying to unit-test a class that extends an abstract base class
.
Here are the "similar classes" for illustration purposes:
public abstract class MyAbstractBaseClass {
@Autowired
private WaterFilter waterFilter;
protected List<String> filterComponents(List<String> allComponents) {
return waterFilter.filter(allComponents);
}
}
public class MyDerivedClass extends MyAbstractBaseClass {
public List<String> filterWater(List<String> allWaterComponents) {
List<String> filteredComponents = this.filterComponents(allWaterComponents); //calls abstract class's filterComponets()
filteredComponents.add("something-else");
return filteredComponents;
}
}
Here is the unit test I am trying:
@RunWith(EasyMockRunner.class)
public class MyDerivedClassTest {
@TestSubject
private MyDerivedClassTest SUT;
@Before
public void setup() {
SUT = new MyDerivedClassTest();
}
@Test
public void test filterWater_HappyCase() {
//I want to mock my abstract class's filterComponents() method
//I am trying this:
EasyMock.expect(SUT.filterComponents(getDummyComponents())).andReturn(getSomeComponents());
//What to replay here?
//EasyMock.replay(...)
List<String> actualResult = SUT.filterWater(getDummyComponents());
//assert something
//What to verify?
//EasyMock.verify(...)
}
}
When I run this test, I get
java.lang.NullPointerException
in MyAbstractBaseClass.filter(allComponents)
I understand that the autowired "waterFilter" is not getting initialized. But then, I just want to mock the "non-abstract" method of the abstract class
in my unit test.
How should I go about this using EasyMock? Also, I don't know what to replay()
and verify()
.
Upvotes: 2
Views: 1872
Reputation: 131376
When you write an unit test, you test a object (generally, a method of it) and you may mock a object (generally, a method of it).
However, you should not unit test and mock the same object because in a some way, it seems not very natural : if you test a method of a class, the behavior of the tested class should stay as natural as possible and not fake its own methods.
Otherwise, we can wonder if the quality of the unit test is good.
Why ? Because it doesn't reflect the real behavior of the class that we would have at the runtime, but just some part of its behavior.
In a unit test, isolation is researched but behind it, the idea is to isolate your under test class only from the other classes and not an isolation of its own behavior.
Of course, you can try to mock a no-abstract method in the abstract class of your under tested class but the design and the quality of your test may become less good.
In your case, I imagine two reasons to mock the no-abstract method in the abstract class :
waterFilter
field dependency annoys you because it is not valued, so an exception (NullPointerException) is raised during the test.1) If your the problem is the waterFilter
field dependency.
you should mock the waterFilter
field. To mock a field, it must be accessible and modifiable. In your case, it's not straight because the field is private.
So, you have two ways to access to it to be able to mock it :
MyDerivedClass
.You don't need to do verify operations with EasyMock. Just mock the result returned by waterFilter.filter(allComponents)
such as :
waterFilterMock.filter(mockedComponents)
In this way, the mock returns the value you have chosen and in your JUnit assertion, you are able to do the correct assertion for your method under test.
Just for information, you could use Mockito instead of EasyMock. It's more flexible and it offers more readable operations. For example, you could do it with Mockito :
Mockito.when(waterFilterMock.filter()).thenReturn(mockedComponents);
As you can see, it is more readable.
2) If you problem is that you really want to mock the no-abstract method in the abstract class because you have already unitary tested it
You should modify your design and use composition instead of inheritance. You would have not MyAbstractBaseClass
any longer but simply a dependency between two classes (the one has a field of the other). In this way, you could mock the filterComponents()
method in a natural way.
Upvotes: 3
Reputation: 395
Expectations has to be set on mocked resources. In your case i think you should inject a mocked instance of WaterFilter.
And your expectation,replay and verify should be set on waterFilter object instance.
You can refer to the example provided in given below link. http://www.tutorialspoint.com/easymock/easymock_junit_integration.htm
Upvotes: 0