Как использовать JMock для тестирования имитируемых методов внутри имитируемого метода

Мне сложно определить, как имитировать конкретный фрагмент кода.

Вот мой метод:

public void sendNotifications(NotificationType type, Person person)
    {
        List<Notification> notifications = findNotifications(type);
        for(Notification notification : notifications)
        {
            notification.send(person);
        }
    }

Я хотел бы иметь возможность использовать JMock для проверки того, что вызывается findNotifications и что он возвращает ожидаемое значение и что вызывается send ().

findNotifications вызывает мой Дао, над которым издеваются. Уведомление - это абстрактный класс.

У меня есть такой модульный тест, но он явно не работает. Он удовлетворяет первые два ожидания, но не более того.

    @Test
public void testSendNotifications2()
{
    final Person person = new Person();
    notificationEntries.add(createEntry1);

    Mockery context = new JUnit4Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }};
    final NotificationDao dao = context.mock(NotificationDao.class, "notificationDao");
    final Notification mockedNotification = context.mock(V2ADTNotification.class, "mockNotification");
    notifications.add(mockedNotification);

    final NotifierServiceImpl mockedService = context.mock(NotifierServiceImpl.class, "mockedService");

    //NotifierService service = new NotifierServiceImpl(dao);

    context.checking(new Expectations() {
        {
            one(mockedService).setDao(dao);
            one(mockedService).sendNotifications(NotificationType.CREATE, person);
            one(mockedService).findNotifications(NotificationType.CREATE);
            one(dao).getByNotificationType(NotificationType.CREATE);
            will(returnValue(notificationEntries)); 
            will(returnValue(notifications));

            one(mockedNotification).send(person);
        }
    });

    mockedService.setDao(dao);
    mockedService.sendNotifications(NotificationType.CREATE, person);
    context.assertIsSatisfied();
}

    mockedService.sendNotifications(NotificationType.CREATE, person);
    context.assertIsSatisfied();
}

Как я могу заставить это работать так, как я хочу?

Другой способ я пробовал. Он удовлетворяет первые два ожидания, но не отправляет.

@Test
public void testSendNotifications()
{
    final Person person = new Person();
    notificationEntries.add(createEntry1);

    Mockery context = new JUnit4Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }};
    final NotificationDao dao = context.mock(NotificationDao.class, "notificationDao");
    final Notification mockedNotification = context.mock(V2ADTNotification.class, "mockNotification");

    NotifierService service = new NotifierServiceImpl(dao);

    context.checking(new Expectations() {
        {
            one(dao).getByNotificationType(NotificationType.CREATE);
            will(returnValue(notificationEntries)); 

            one(mockedNotification).send(person);
        }
    });

    service.sendNotifications(NotificationType.CREATE, person);
    context.assertIsSatisfied();
}

Я новичок в использовании Jmock, поэтому прошу прощения, если не похоже, что я понимаю, что делаю (а я нет).


person AHungerArtist    schedule 13.04.2011    source источник


Ответы (1)


тестируйте имитируемые методы внутри имитируемого метода.

Вы действительно просто не можете этого сделать. Вызовы в реальном методе не выполняются, потому что вы вызываете фиктивный метод вместо реального метода.

Ваша первая попытка не оправдывает двух последних ожиданий, потому что вызовы, которые заставили бы их пройти, выполняются только в реальной реализации sendNotifications, а не в макете, который вы сделали над ним.

Второй вариант ближе к рабочему, но вам нужно добавить свой mockedNotification в список notificationEntries, который вы настроили для возврата с помощью имитации getByNotificationType.

person Don Roby    schedule 13.04.2011
comment
Я так и думал, но не знал наверняка, упустил ли я что-то. Я выбрал другой путь. Внутри метода findNotifications я использовал статическую фабрику. Я решил сделать фабрику инъекционным классом, а не статическим, так что теперь я издеваюсь над ним и могу протестировать поведение, которое хочу (иначе я бы никогда не смог получить имитируемые объекты уведомлений вместо только имитируемые объекты NotificationEntry - вероятно, следовало включить больше кода). Я отмечу ваш ответ как правильный, поскольку он решает мою проблему, и я объяснил свое решение в этом комментарии. - person AHungerArtist; 14.04.2011