I’m wondering how to go about checking that a method returns a container encapsulating some collection which is the aggregate of multiple other containers returned by mock objects. That is, it contains all the elements of the individual containers. I have some tests elsewhere that check the container ‘works’ (add/addAll/etc), so I know that works, but I’m not sure how go about with the test below ‘createsRoadUsersAccordingToAllAddedCreators’.
I have a RoadUserCreationDaemon class which I call create upon which returns a RoadUserContainer according to added RoadUserCreator’s. A simplified version:
public class RoadUserCreationDaemon {
private SimulationManager simulationManager;
private List<RoadUserCreator> roadUserCreators;
public RoadUserCreationDaemon(SimulationManager simulationManager) {
this.simulationManager = simulationManager;
roadUserCreators = new ArrayList<RoadUserCreator>();
}
public void addRoadUserCreator(RoadUserCreator roadUserCreator) {
roadUserCreators.add(roadUserCreator);
}
public RoadUserContainer createRoadUsers() {
RoadUserContainer roadUsers = new RoadUserContainerImpl();
for (RoadUserCreator creator : roadUserCreators) {
roadUsers.addAll(createRoadUsers(creator));
}
return roadUsers;
}
public RoadUserContainer createRoadUsers(
RoadUserCreator roadUserCreator) {
return roadUserCreator.create();
}
}
I started by writing a test (JUnit4 / JMock2.5.1) for createRoadUsers which returns a RoadUserContainer with a supplied creator. Then I started writing a test for a non-parameterised createRoadUsers to see if it returns a container with all the elements of the individual containers returned by the creators:
@RunWith(JMock.class)
public class TestRoadUserCreationDaemon {
Mockery context = new JUnit4Mockery();
private RoadUserCreationDaemon daemon;
private RoadUserCreator roadUserCreator;
private SimulationManager simulationManager;
private RoadUserContainer createdRoadUsers;
@Before
public void setUp() {
simulationManager = context.mock(SimulationManager.class);
daemon = new RoadUserCreationDaemon(simulationManager);
roadUserCreator = context.mock(RoadUserCreator.class);
createdRoadUsers = context.mock(RoadUserContainer.class);
}
@Test
public void createsRoadUsersAccordingToAllAddedCreators() throws Exception {
final RoadUserCreator anotherRoadUserCreator = context.mock(RoadUserCreator.class, "anotherRUC");
final RoadUserContainer moreCreatedRoadUsers = context.mock(RoadUserContainer.class, "moreCRU");
context.checking(new Expectations() {{
oneOf (roadUserCreator).create(); will(returnValue(createdRoadUsers));
oneOf (anotherRoadUserCreator).create(); will(returnValue(moreCreatedRoadUsers));
oneOf (createdRoadUsers).roadUsersAsList();
oneOf (moreCreatedRoadUsers).roadUsersAsList();
}});
daemon.addRoadUserCreator(roadUserCreator);
daemon.addRoadUserCreator(anotherRoadUserCreator);
daemon.createRoadUsers();
//how to easily check that the two lists are equivilant - have same items, but not the same object?
//assertEquals(createdRoadUsers, daemon.createRoadUsers() );
}
@Test
public void createsRoadUsersAccordingToCreator() throws Exception {
context.checking(new Expectations() {{
oneOf (roadUserCreator).create(); will(returnValue(createdRoadUsers));
}});
assertEquals(createdRoadUsers, daemon.createRoadUsers(roadUserCreator));
}
}
As the comment says…I’m not sure how to proceed in a non-ugly way.
The ‘RoadUserContainer’ interface:
public interface RoadUserContainer extends Iterable<RoadUser> {
public void add(RoadUser roadUser);
public Iterator<RoadUser> iterator();
public void addAll(RoadUserContainer createRoadUsers);
public List<RoadUser> roadUsersAsList();
public boolean equals(RoadUserContainer otherContainer);
...
}
I am new to TDD and mocking, and this is my first Java project for >6 years, so feel free to comment on ancillary aesthetics!
I would probably initially use real containers and mock the other objects. Then use hamcrest to interrogate the resulting object.
The test I would want to create would look something like this:
you will need these imports from hamcrest:
If order is not important you could use containsInAnyOrder instead of contains
you would also need to create the utility method “roadUsers”
An alternative design would be to change the interface of the RoadUserCreationDaemon
Then you could write the tests like this:
If the order of the calls to “addAll” is important you can use a jmock sequence