Как избежать ложных срабатываний, используя mockist подход в модульных тестах? - PullRequest
3 голосов
/ 30 сентября 2010

Поскольку структура данных моего домена приложений в последнее время становится довольно сложной, я начал читать фиктивные объекты. Вскоре мне пришёл в голову простой вопрос, но ответ оказался головной болью. Итак, вот так:

У нас есть класс 'Foo' с 'bar' в качестве одного из его методов:

class Foo {
    public String bar(int i){
        if(i == 1) return "arrr!";
    }
}

И у нас есть класс Pirate, вызывающий Foo.bar (1); в одном из его методов:

class Pirate {
    public String yell(){
        Foo foo = new Foo();
        return foo.bar(1);
    }

Теперь мы высмеиваем класс Foo в модульном тесте класса Pirate, потому что у Foo есть множество других зависимостей:

@Test
public void returnsPirateString() {
    Pirate blackBeard = new Pirate();
    Foo fooMock = mock(Foo.class);
    fooMock.expectAndReturn("bar",1,"arrr!"); //expects 'bar' function to be called once and returns "arrr!"
    assertEquals(blackBeard.yell(),"arrr!");
}

Что происходит сейчас, так это то, что если мы рефакторим метод bar, чтобы вернуть null вместо «arrr!», Наш тест будет работать успешно, пока наша программа не будет работать так, как мы этого хотим. Это может привести к возможному кошмару отладки.

Использование подхода mockist вместо классического подхода тестирования к модульному тестированию, в большинстве случаев все «вспомогательные» объекты подвергаются моделированию, и только проверенный объект остается неизменным, поэтому ранее заявленная проблема может возникать довольно часто.

Что можно сделать, чтобы предотвратить эту проблему во время издевательств?

Ответы [ 3 ]

3 голосов
/ 30 сентября 2010

В своем тесте вы тестируете метод yell () класса Pirate, который использует Foo. Таким образом, вы должны высмеивать поведение метода бара Фу. Чтобы убедиться, что ваш метод bar работает правильно, вам нужен еще один тестовый пример для проверки метода bar из Foo.

@Test
public void testBar() {
   //make sure bar retrun "arrr"!
}

Теперь, если ваш метод bar возвращает ноль, этот тестовый пример не пройден!

2 голосов
/ 30 сентября 2010

Вы должны также тестировать «вспомогательный объект» отдельно. После того, как оба они пройдут тестирование, вы можете быть уверены, что оба они взаимодействуют друг с другом ожидаемым образом.

Изменение вашего «вспомогательного объекта» - это то, что должно быть сделано с помощью тестов для этого вспомогательного объекта, чтобы подтвердить, что он по-прежнему ведет себя как ожидалось.

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

0 голосов
/ 30 сентября 2010

Тест returnsPirateString - это , а не ложное срабатывание - он проверяет, что происходит, когда Pirate '* Foo экземпляр возвращает' arrr! '

Другими словами,когда вы тестируете Pirate.yell, , не имеет значения, что Foo.bar возвращает , если только это не создает специальное граничное условие (и у вас, вероятно, уже должен быть тест, который документируетчто yell делает, когда Foo возвращает null).

Pirate.yell не несет ответственности за гарантию какого-либо конкретного возвращаемого значения для Foo.bar, поэтому его модульные тесты не должны ожидать каких-либо конкретных возвращаемых значений.Вам даже следует поменять свой тест на использование чего-либо, кроме текущего возвращаемого значения Foo.bar.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...