Let's say I have the following classes in the respective source folders/packages...
[src/myApp]
|_Employee «concrete»
|_Manager «abstract»
|_ManagerImpl «concrete» (Class Under Test)
|_Recruiter «abstract»
|_RecruiterImpl «concrete» (Collaborator)
...
public class ManagerImpl implements Manager {
...
private Recruiter recR;
...
public void growTeam( Object criteria ){
//...check preconditions
Employee newB = recR.srcEmployee( criteria );
//...whatever else
}
...
}
...
[test/myApp]
|_RecruiterStandIn «concrete»
|_ManagerImplTest
...
public class RecruiterStandIn implements Recruiter {
Map<Object, Employee> reSrcPool = new HashMap<>();
public RecruiterStandIn( ){
// populate reSrcPool with dummy test data...
}
public Employee srcEmployee( Object criteria ){
return reSrcPool.get( criteria );
}
}
...
public class ManagerImplTest {
...
// Class Under Test
private ManagerImpl mgr;
// Collaborator
private Recruiter recR = new RecruiterStandIn( );
...
public void testGrowTeam( ) {
//...
mgr.setRecruiter( recR );
mgr.growTeam( criteria );
// assertions follow...
}
...
}
...
Here are my questions: Given that I have a RecruiterStandIn
concrete implementation that already exists within the codebase for testing purposes (in the test
scope)...
Would it be redundant to also use a mock in the above unit test?
What would be the value (if any) in additionally doing something like this in the above unit test?
...
...
@Mock
private Recruiter recR;
...
...
public void testGrowTeam( ) {
...
expect( recR.srcEmployee( blah) ).andReturn( blah )...
// exercising/assertions/validations as usual...
}
...
You can safely assume that RecruiterStandIn
does everything the class under test will ever require of it for the purposes of the above unit test. That is to say, for the sake of simple answers/explanations, there's no need to overcomplicate the above scenario with contrived what-ifs around maintenance of the stub and whatnot.
Thanks in advance.
My answers to your specific questions:
As the unit test is written right now it would be redundant but my see answer to your second question below.
It think this is the way you should be doing your tests and I would recommend getting rid of your stub, RecruiterStandIn
. Instead I would setup the recruit to return canned answers so you don't have to maintain two classes just to return some predefined data:
@Spy
private Recruiter recR;
public void testGrowTeam( ) {
// Setup canned data return
doReturn(generateTestEmployee()).when(recR).srcEmployee(any(Object.class));
expect( recR.srcEmployee( blah) ).andReturn( blah )...
// exercising/assertions/validations as usual...
}
FYI the above syntax would be for using Mockito. From what I can tell in your case Mockito gives you the power of stubbing out certain parts and much more without requiring you to create new test entities.
Original Answer
Definitely yes you should be doing mock object tests. Mocks Aren't Stubs. Mock object testing allows you to test the interactions between your classes and ensure that things are interacting with the world around them correctly. I think there is less value in these tests when you first write the classes and their corresponding tests. Mock object tests shine a year down the road when a new developer comes in and inadvertently your breaks code because she didn't understand that certain internal behavior was needed..
A somewhat contrived example would be if let's say we had a Car that needed to fill up some gas:
public class Car {
public void fuelUp()
}
Now with standard unit tests we would check that after calling fuelUp()
the car was full of gas and that the proper amount of money was deducted from the driver. But since we never tested how fuelUp()
was interacting with the world around it, it could easily be doing the following:
public void fueldUp() {
siphonGasFromNearestCar();
buyCoffeeAndChips()
}
But with mock object testing you can ensure that the Car is getting filled up in the proper and expected way.