Как часто используются ложные объекты?

15

Недавно я прочитал статью, в которой говорилось, что фиктивные объекты часто неправильно понимают и неправильно используют. Есть ли какие-то явные насмешливые анти-паттерны, на которые я могу обратить внимание?

Armand
источник
это статья, которую вы прочитали? martinfowler.com/articles/mocksArentStubs.html
keppla
нет ... не могу вспомнить точный источник, но опубликую здесь, если я это сделаю
Armand
Я был взят на задание на stackoverflow для насмешки над mongodb API. Мне указали на сообщение в блоге, в котором утверждалось, что издеваться над любым классом, который вы сами не написали, неправильно. Я на самом деле не согласен с этим, но мнение там.
Кевин

Ответы:

13

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

public class Person
{
    private readonly string _firstName;
    private readonly string _surname;

    public Person(string firstName, string surname)
    {
        if (String.IsNullOrEmpty(firstName))
        {
            throw new ArgumentException("Must have first name");
        }

        if (String.IsNullOrEmpty(surname))
        {
            throw new ArgumentException("Must have a surname");
        }

        _firstName = firstName;
        _surname = surname;
    }

    public string Name 
    {
        get
        {
            return _firstName + " " + _surname;
        }
    }
}

В любых тестах, связанных с этим классом, я бы предпочел создать настоящий экземпляр и использовать его, а не какой-нибудь интерфейс, такой как «IPerson», который использовался как поддельный и ожидание. Используя реальный тест, вы получаете более реалистичный тест (у вас есть проверка параметров и реальная реализация свойства Name). Для такого простого класса, как этот, вы не делаете свои тесты медленнее, менее детерминированными или не запутываете логику (вам вряд ли нужно знать, что Name вызывалось при тестировании какого-либо другого класса) - что является обычными причинами насмешек гася.

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

FinnNk
источник
К счастью, мокирующие фреймворки, которые я использовал, смогли имитировать конкретные классы, так что вытащить интерфейсы в неудобных местах не проблема.
Арманд
5
Это не меняет проблему - такого рода простые вещи, как правило, не должны быть смоделированы, даже если вы используете что-то, что ослабляет технические ограничения на то, что можно смоделировать (например, макет фреймворка, такой как TypeMock или динамический язык).
FinnNk
Моим эмпирическим правилом всегда было издеваться над поведением, а не за данными.
ardave
10

Это может показаться очевидным, но: не используйте фиктивные объекты в производственном коде! Я видел более одного примера, где рабочий код зависел от характеристик определенных фиктивных объектов (например, MockHttpServletRequestот Springframework).

perdian
источник
14
я надеюсь, что вы выполнили свой священный долг и передали код DailyWTF?
Кеппла
1
В моей предыдущей работе нам было категорически запрещено передавать что-либо из нашей кодовой базы в DWTF.
Quant_Dev
9
@quant_dev: Тот факт, что у них была такая политика, подразумевает страшные вещи об их разработчиках ...
Джон Фишер
1
На самом деле, нет. Это был стартап, который должен был быстро разработать кодовую базу для продажи продукта, а затем начал консолидировать и реорганизовывать его для погашения технического долга, поскольку продукт созрел и дальнейшее развитие было затруднено (отсутствием) первоначального дизайна. Менеджеры знали, что старая кодовая база - дерьмо, и вкладывали время и ресурсы в рефакторинг, но не хотели рисковать какой-либо негативной рекламой.
quant_dev
Просто использовать ярлыки не достаточно, чтобы получить вас только ежедневноwtf ...
Poolie
9

На мой взгляд, это чрезмерная проверка вызова метода на макетах. Я чувствую, что это практика, применяемая несколькими модельными фреймворками, такими как EasyMock, где по умолчанию имитируется поведение по умолчанию, когда происходит дополнительный вызов метода, который не был точно указан ранее. Этот вид строгой проверки ложных методов может привести к хрупким конструкциям, где малейшие изменения в коде могут привести к сбою целого набора тестов, даже несмотря на то, что основные функции остаются прежними.

Решением этой проблемы является использование заглушек вместо макетов. Статья, которую я нашел особенно поучительной по этому вопросу, была найдена в Javadoc Mockito: http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html (см. «2. Как насчет заглушки?» ), ссылка на: http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-unexpected/ .

До сих пор мне нравилось работать с Mockito, потому что он не требует такого строгого насмешливого поведения, а вместо этого использует заглушки. Он также обеспечивает проверку методов на определенных объектах вместо всего фиктивного объекта; таким образом, вы в конечном итоге проверяете только те методы, которые действительно имеют значение в вашем тестовом сценарии

Здесь и там есть несколько книг, которые я могу порекомендовать затронуть эту тему, насмешливые и общие:

Шаблоны xUnit

Искусство модульного тестирования: с примерами в .Net

Тестирование Java следующего поколения: TestNG и расширенные концепции (эта книга в основном посвящена testNG, но есть хорошая глава о насмешках)

Фабио Кенджи
источник
+1 за пункт о чрезмерных проверках вызова метода. Однако всегда есть оборотная сторона медали, где неожиданный вызов метода вызывает сбой в вашем методе. К счастью, у Mockito есть Answer.RETURNS_SMART_NULLSнастройка для насмешек, которая помогает диагностировать это.
Bringer128
4

Я наблюдал немного анти-паттернов в моем опыте.

  • Классы доменов подвергаются насмешкам / заглушкам, когда может произойти изменение состояния, и это необходимо проверить.
  • Интеграционные тесты взаимодействуют со смесью макетов и конкретных классов, что противоречит цели интеграционных тестов.
  • Непреднамеренное использование макетов в рабочем коде (этого никогда не должно происходить)

В противном случае мой опыт работы с издевательствами, особенно Mockito, был легким. Они сделали тесты очень простыми в написании и обслуживании. GWT-тестирование взаимодействия между представителем и представителем намного проще с макетами, чем GWTTestCase.

Винод Р
источник
2 и 3 являются определенными проблемами! У вас есть простой пример (1)?
Арманд
2

Я считаю, что тесты, которые используют макеты на нескольких уровнях приложения, особенно трудно расшифровать и изменить. Однако я думаю, что это было смягчено в последние годы улучшенными API фальшивых фреймворков (я использую JMock, где это удобно).

5 или 6 лет назад API, такие как EasyMock, были мощными, но очень громоздкими. Часто тестовый код, который использовал его, был на несколько порядков сложнее, чем код, который он тестировал. В то время я пытался влиять на команды, в которых я был, чтобы использовать их очень экономно и обходиться простыми мошенничествами ручной работы, которые были просто альтернативными реализациями интерфейсов специально для тестирования.

В последнее время мои сильные мнения об этом стали мягче, поскольку API-интерфейсы для проверки сделали тесты, использующие их, более читабельными. По сути, я хочу, чтобы мой код (включая тесты) мог изменяться другими разработчиками, чтобы они не чувствовали себя так, как будто отбирают множество непонятных вызовов API.

rupjones
источник