Mockito проверяет состояние в середине теста - PullRequest
1 голос
/ 07 июля 2011

У меня есть простой код, который устанавливает объект в состояние ОБРАБОТКА, выполняет некоторые вещи, а затем устанавливает его на УСПЕХ. Я хочу убедиться, что сохранение выполняется с правильными значениями.

Проблема в том, что когда выполняются тесты verify (), .equals() вызывается для объекта в том виде, в каком он есть в конце теста, а не на полпути.

Например, код:

public void process(Thing thing) {
    thing.setValue(17);
    thing.setStatus(Status.PROCESSING);
    dao.save(thing);

    doSomeMajorProcessing(thing);

    thing.setStatus(Status.SUCCESS);
    dao.save(thing);
}

Я хочу проверить:

public void test() {
    Thing actual = new Thing();
    processor.process(actual);

    Thing expected = new Thing();
    expected.setValue(17);
    expected.setStatus(Status.PROCESSING);
    verify(dao).save(expected);

    // ....

    expected.setStatus(Status.SUCCESS);
    verify(dao).save(expected);
}

При первой проверке actual.getStatus() равен Status.SUCCESS, так как Mockito просто сохраняет ссылку на объект и может только проверить его значение в конце.

Я считал, что если when(...) там, где он задействован, то .equals() будет вызван в нужное время, и результат будет только в том случае, если Я хотел, чтобы То было тем, чем я хотел. Однако в этом случае .save() ничего не возвращает.

Как проверить, что объект переведен в правильные состояния?

Ответы [ 4 ]

2 голосов
/ 08 июля 2011

Хорошо, я нашел решение, но оно довольно ужасное. Проверка не годится для меня, потому что она запускается слишком поздно, а заглушка трудна, потому что метод возвращает пустоту. Но что я могу сделать, так это заглушить и выдать исключение, если вызывается что-либо, кроме ожидаемого, при проверке того, что что-то вызывается:

public void test() {
    Thing actual = new Thing();

    Thing expected = new Thing();
    expected.setValue(17);
    expected.setStatus(Status.PROCESSING);

    doThrow(new RuntimeException("save called with wrong object"))
            .when(dao).saveOne(not(expected));

    processor.process(actual);

    verify(dao).saveOne(any(Thing.class));

    // ....

    expected.setStatus(Status.SUCCESS);
    verify(dao).saveTwo(expected);
}

private <T> T not(final T p) {
    return argThat(new ArgumentMatcher<T>() {
        @Override
        public boolean matches(Object arg) {
            return !arg.equals(p);
        }
    });
}

Это означает, что ожидаемый называется. Единственным недостатком является то, что будет сложно проверить метод дважды, но, к счастью, в моем случае оба вызова DAO относятся к разным методам, поэтому я могу проверить их по отдельности.

0 голосов
/ 21 июня 2012

Почему бы просто не посмеяться над самой вещью и убедиться в этом? например:

public class ProcessorTest {

    @Mock
    private Dao mockDao;
    @InjectMocks
    private Processor processor;

    @BeforeMethod   
    public void beforeMethod() {
        initMocks(this);
    }

    public void test() {

        Thing mockThing = Mockito.mock(Thing.class);
        processor.process(thing);

        verify(mockThing).setStatus(Status.PROCESSING);
        verify(mockThing).setValue(17);
        verify(mockDao).save(mockThing);
        verify(mockThing).setStatus(Status.SUCCESS);
    }

Если вы хотите явно проверить порядок, в котором происходят эти вещи, используйте объект InOrder:

public void inOrderTest() {

    Thing mockThing = Mockito.mock(Thing.class);
    InOrder inOrder = Mockito.inOrder(mockThing, mockDao);

    processor.process(mockThing);

    inorder.verify(mockThing).setStatus(Status.PROCESSING);
    inorder.verify(mockThing).setValue(17);
    inorder.verify(mockDao).save(mockThing);
    inorder.verify(mockThing).setStatus(Status.SUCCESS);
    inorder.verify(mockDao).save(mockThing);
}
0 голосов
/ 07 июля 2011

У Mockito есть проблема с проверкой изменчивых объектов.Существует открытая проблема по этому поводу (http://code.google.com/p/mockito/issues/detail?id=126)

Возможно, вам следует переключиться на EasyMock. Они используют шаблон записи / воспроизведения и выполняют проверку во время вызова, в отличие от Mockito, где проверка происходит после вызова.

Эта версия теста Mockito имеет указанную проблему:

@Test
public void testMockito() {
    Processor processor = new Processor();
    Dao dao = Mockito.mock(Dao.class);
    processor.setDao(dao);

    Thing actual = new Thing();
    actual.setValue(17);
    processor.process(actual);

    Thing expected1 = new Thing();
    expected1.setValue(17);
    expected1.setStatus(Status.PROCESSING);
    verify(dao).save(expected1);

    Thing expected2 = new Thing();
    expected2.setValue(19);
    expected2.setStatus(Status.SUCCESS);
    verify(dao).save(expected2);
}

Эта версия EasyMock отлично работает:

@Test
public void testEasymock() {
    Processor processor = new Processor();
    Dao dao = EasyMock.createStrictMock(Dao.class);
    processor.setDao(dao);

    Thing expected1 = new Thing();
    expected1.setValue(17);
    expected1.setStatus(Status.PROCESSING);
    dao.save(expected1);

    Thing expected2 = new Thing();
    expected2.setValue(19);
    expected2.setStatus(Status.SUCCESS);
    dao.save(expected2);

    EasyMock.replay(dao);

    Thing actual = new Thing();
    actual.setValue(17);
    processor.process(actual);

    EasyMock.verify(dao);
}

В моем примере doSomeMajorProcessing sets *От 1012 * до 19.

private void doSomeMajorProcessing(Thing thing) {
    thing.setValue(19);     
}
0 голосов
/ 07 июля 2011

Использование argThat с подколенным сухожилием Matcher должен сделать свое дело.Matcher будет соответствовать переданному ему thing, если вещь имеет статус PROCESSING:

public class ProcessingMatcher extends BaseMatcher<Thing> {
    @Override
    public boolean matches(Object item) {
        if (item instanceof Thing) {
            return ((Thing) item).getStatus() == Status.PROCESSING;
        }
        return false;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText(" has the PROCESSING status");
    }
}

И затем в вашем тесте используйте следующий код:

public class MyTest {

    public void test() {
        //...
        mockDao.save(argThat(hasTheProcessingStatus()));
    }

    static ProcessingMatcher hasTheProcessingStatus() {
        return new ProcessingMatcher();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...