модульное тестирование наилучшей практики для метода с mocks в Mockito - PullRequest
3 голосов
/ 20 апреля 2011

Допустим, у нас есть метод для тестирования в классе A, который вызывает метод из класса B. Чтобы проверить его, мы создали макет для B и затем проверили, был ли он вызван.Достаточно ли проверки (...) для модульного тестирования или мне нужно подтвердить фактический результат проверенного метода?Ниже приведен упрощенный пример для разъяснения моей озабоченности:

public class StringWriterATest {
    StringWriterB b = mock(StringWriterB.class);

    @Test
    public void stringWriterATest() {
        StringBuffer sb = new StringBuffer();
        StringWriterA a = new StringWriterA();
        a.stringWriterB=b;

        a.append(sb);

        ArgumentCaptor<StringBuffer> argument = ArgumentCaptor.forClass(StringBuffer.class);
        verify(b).append(argument.capture());

        assertEquals("StringWriterA", ((StringBuffer)argument.getValue()).toString());

        //do we really need this or above is enough for proper unit test of method a.append(sb); 
        //assertEquals("StringWriterA_StringWriterB", sb);
    }
}


public class StringWriterA {
    public StringWriterB stringWriterB;

    public void append(StringBuffer sb) {
        sb.append("StringWriterA");
        stringWriterB.append(sb);
    }
}

class StringWriterB {
    public void append(StringBuffer sb) {
        sb.append("StringWriterB");
    }
}

С уважением, Макс

Ответы [ 3 ]

1 голос
/ 25 апреля 2012

Никогда не нужно издеваться над возвращаемым значением и проверять объект одновременно.

Учитывайте следующее:

StringWriterA - это тестируемый класс.Поэтому вы определенно захотите использовать утверждения для проверки поведения этого класса.Для этого вы макетируете зависимость: StringWriterB.

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

Вы должны предположить, что StringWriterB ведет себя как ожидалось.Вы либо хотите убедиться, что StringWriterA правильно вызвал StringWriterB (используя verify()) или , вы хотите смоделировать его ожидаемое поведение и смоделировать возвращаемые значения.тогда проверка неявна, так как ложное возвращаемое значение не будет возвращено, если метод не вызывается.

В вашем случае StringWriterA.append() не возвращает никакого значения, поэтому возможна только проверка.То, что StringWriterB.append() также работает, должно иметь аналогичный тест верификации в stringWriterBTest.

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

<underTest>Should<Expected>[When]<Condition>()

т. Е.

stringWriterAShouldAppendConstantAndDelegateToStringWriterB() stringWriterAShouldThrowNullPointerExceptionWhenNullArgument()

Если в вашей сборке есть неудачные тесты (непрерывная интеграция), тогда вам не нужно выискивать, что пошло не так, имя метода отображается правильно после сбоя, и вы можете прочитать его, чтобы точно знать, какое поведение должно быть исправлено.

0 голосов
/ 02 июля 2012

Прежде всего попробуйте показать кому-нибудь тест, который вы написали .Трудно читать по моему мнению. Вы не можете точно сказать, какое поведение вы тестируете .Краткое введение для вас, как сделать его немного более читабельным, можно найти здесь Как писать чистый, тестируемый код .Использование захватчиков аргументов также является запахом.Некоторые примеры того, как этого избежать, можно найти в этом tdd блоге .

Чтобы ответить на ваш вопрос , verify используется для проверки взаимодействий между классами. Он используется для управления дизайном вашего кода. Результат (при необходимости) должен быть указан when или given в начале вашего теста.

Дополнительную информацию о том, как управлять своим дизайном с помощью макетов (when, given, verify, ...) и как макеты отличаются от заглушек, можно найти здесь: Макеты не являются заглушками .В этом примере для определения макетов используется JMock, а не Mockito, но он очень похож (он касается концепций, а не деталей реализации и используемых вами библиотек).

0 голосов
/ 20 апреля 2011

В вашем примере StringWriterB не хранит состояния, а метод append может легко быть статическим. В этом случае вызов является чисто побочным эффектом и не нуждается в проверке.

Однако я подозреваю, что ваш реальный код намного сложнее. Если есть другой объект, который обращается к StringWriterB, вы можете его смоделировать на случай непредвиденных вызовов. Вы также можете добавить подтверждение B, если ожидаете, что оно будет расширено в будущем - возможно, сохранение состояния от вызова добавления и наличие средств доступа.

Одна вещь, которую нужно рассмотреть, это то, что является целью вызова StringWriterA.append(). Если работа заключается в добавлении строки StringWriterAStringWriterB, то это то, что вы должны тестировать, и макет не нужен. То, как StringWriterA выполняет эту задачу, не имеет значения. Однако, если часть его работы также заключается в вызове метода StringWriterB.append(), тогда может потребоваться имитация, если вы не хотите проверить StringWriterB в тесте А.

Мое эмпирическое правило WRT - использовать реальные объекты, пока проводка для объектов, которые я не тестирую напрямую, не станет слишком волосатой или слишком хрупкой. Если я чувствую, что значительная часть моих тестов в действительности тестирует другие объекты, тогда имитация будет хорошей идеей.

...