Насмешливые объекты, которые инкапсулируют коллекции - PullRequest
2 голосов
/ 17 октября 2011

Мне интересно, как проверить, что метод возвращает контейнер, инкапсулирующий некоторую коллекцию, которая является совокупностью нескольких других контейнеров, возвращаемых фиктивными объектами. То есть он содержит все элементы отдельных контейнеров. У меня есть несколько тестов в другом месте, которые проверяют контейнер «работает» (add / addAll / etc), поэтому я знаю, что он работает, но я не уверен, как обстоят дела с тестом ниже «createRoadUsersAccordingToAllAddedCreators».

У меня есть класс RoadUserCreationDaemon, который я вызываю create, который возвращает RoadUserContainer в соответствии с добавленным RoadUserCreator. Упрощенная версия:

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();
    }
}

Я начал с написания теста (JUnit4 / JMock2.5.1) для createRoadUsers, который возвращает RoadUserContainer с предоставленным создателем. Затем я начал писать тест для непараметризованного createRoadUsers, чтобы увидеть, возвращает ли он контейнер со всеми элементами отдельных контейнеров, возвращенных создателями:

@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));
    }
}

Как говорится в комментарии ... Я не уверен, как поступить безобразно.

Интерфейс RoadUserContainer:

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);
    ...
}

Я новичок в TDD и в насмешках, и это мой первый Java-проект за> 6 лет, так что не стесняйтесь комментировать вспомогательную эстетику!

Ответы [ 2 ]

2 голосов
/ 20 октября 2011

Сначала я бы использовал реальные контейнеры и высмеивал другие объекты.Затем используйте hamcrest для опроса полученного объекта.

Тест, который я хотел бы создать, выглядел бы примерно так:

final RoadUser roadUser0 = context.mock(RoadUser.class, "roadUser0");
final RoadUser roadUser1 = context.mock(RoadUser.class, "roadUser1");
final RoadUser roadUser2 = context.mock(RoadUser.class, "roadUser2");

final RoadUserCreator roadUserCreator0 = context.mock(RoadUserCreator.class, "roadUserCreator0");
final RoadUserCreator roadUserCreator1 = context.mock(RoadUserCreator.class, "roadUserCreator1");

final RoadUserCreationDaemon daemon = new RoadUserCreationDaemon(null);
daemon.addRoadUserCreator(roadUserCreator0);
daemon.addRoadUserCreator(roadUserCreator1);        

context.checking(new Expectations() {{
    oneOf(roadUserCreator0).create(); will(returnValue(roadUsers(roadUser0, roadUser1)));
    oneOf(roadUserCreator1).create(); will(returnValue(roadUsers(roadUser2)));
}});

assertThat(daemon.createRoadUsers(), contains(roadUser0, roadUser1, roadUser2));

вам понадобится этот импорт из hamcrest:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;

Если порядок не важенвы могли бы использовать containsInAnyOrder вместо Содержит

, вам также необходимо создать служебный метод "roadUsers"

public static RoadUserContainer roadUsers(final RoadUser... roadUsers)
{
    return new RoadUserContainerImpl(roadUsers);
}

Альтернативный вариант - изменить интерфейс RoadUserCreationDaemon

public void createRoadUsers(final RoadUserContainer roadUsers) {
    for (final RoadUserCreator roadUserCreator : roadUserCreators) {
        roadUsers.addAll(roadUserCreator.create());
    }
}

Тогда вы могли бы написать тесты следующим образом:

final RoadUserContainer roadUserContainer0 = context.mock(RoadUserContainer.class, "roadUserContainer0");
final RoadUserContainer roadUserContainer1 = context.mock(RoadUserContainer.class, "roadUserContainer1");

final RoadUserContainer resultRoadUserContainer = context.mock(RoadUserContainer.class, "resultRoadUserContainer");

final RoadUserCreator roadUserCreator0 = context.mock(RoadUserCreator.class, "roadUserCreator0");
final RoadUserCreator roadUserCreator1 = context.mock(RoadUserCreator.class, "roadUserCreator1");

final RoadUserCreationDaemon daemon = new RoadUserCreationDaemon(null);
daemon.addRoadUserCreator(roadUserCreator0);
daemon.addRoadUserCreator(roadUserCreator1);

context.checking(new Expectations() {
    {
        oneOf(roadUserCreator0).create();
        will(returnValue(roadUserContainer0));
        oneOf(roadUserCreator1).create();
        will(returnValue(roadUserContainer1));

        oneOf(resultRoadUserContainer).addAll(roadUserContainer0);
        oneOf(resultRoadUserContainer).addAll(roadUserContainer1);
    }
});

daemon.createRoadUsers(resultRoadUserContainer);

Если важен порядок вызовов addAll, вы можете использовать последовательность jmock

1 голос
/ 17 октября 2011

Думаю, я бы издевался над Создателем, но заставил бы его вернуть настоящие Контейнеры. Идея теста состоит в том, чтобы убедиться, что демон вызвал все методы создания создателя, верно? Таким образом, ваше условие теста будет выглядеть как

  RoadUserContainer result = daemon.createRoadUsers();

  // Check that the result contains both creator's users
  Assert.assertEquals(createdRoadUsers.size() + moreCreatedRoadUsers.size(), result.size());

  for (RoadUser user : createdRoadUsers)
      Assert.assertTrue(result.contains(user));
  for (RoadUser user : moreCreatedRoadUsers)
      Assert.assertTrue(result.contains(user));
...