Как вы проводите модульное тестирование класса, который зависит от многих других классов? - PullRequest
6 голосов
/ 06 декабря 2008

Я слышал, что с помощью модульного тестирования мы можем обнаружить большинство ошибок в коде, и я действительно верю, что это правда. Но мой вопрос в больших проектах, где каждый класс зависит от многих других классов. Как вы проводите модульное тестирование класса? Уничтожение любого другого класса не имеет особого смысла из-за сложности и времени, необходимого для написания заглушек. Что вы думаете об этом?

Ответы [ 9 ]

12 голосов
/ 06 декабря 2008

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

Поскольку вы вводите тесты в существующую кодовую базу, вы, несомненно, столкнетесь со многими сложными для тестирования ситуациями, которые потребуют рефакторинга для правильного тестирования. Этот рефакторинг повысит тестируемость вашего кода, одновременно уменьшая зависимости.

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

4 голосов
/ 06 декабря 2008

Используйте насмешливый фреймворк, чтобы заглушки для вас. Фреймворки Mocking (я использую Rhino Mocks для C # /. NET) позволяют довольно легко избавиться от ваших зависимостей. Используемые с внедрением зависимостей, ваши классы можно легко отделить от других классов, и для их создания не требуется много работы. Обратите внимание, что иногда становится легче «подделать» что-то, а не издеваться. Я заканчиваю тем, что подделываю несколько классов, но обычно их довольно легко написать - они просто содержат «хорошие» или «плохие» данные и возвращают их. Никакой логики.

0 голосов
/ 12 декабря 2016

Вот принципы, которые хорошо сработали для нас как для тестируемости, так и для надежного проектирования в очень крупном корпоративном проекте:

  1. Сделайте ваши зависимости явными, передав их через конструкторы классов.

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

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

0 голосов
/ 04 марта 2013

Я чувствую, что вам может потребоваться рефакторинг, чтобы уменьшить сложность.

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

0 голосов
/ 06 декабря 2008

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

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

Иногда проще издеваться над объектом: когда

  • объект является или использует внешний ресурс, такой как база данных или сетевое соединение, диск
  • объект представляет собой графический интерфейс
  • объект еще недоступен
  • поведение объекта не является детерминированным
  • объект дорог в настройке
0 голосов
/ 06 декабря 2008

Но мой вопрос в крупных проектах где каждый класс зависит от многих другие классы, как вы идете о блоке тестирование класса?

Во-первых, вы понимаете, что "каждый класс зависит от многих других классов" - это плохо, верно? И что это не функция большого проекта, а скорее плохой дизайн? (Это одно из преимуществ TDD в том, что он препятствует такому высокосвязанному коду.)

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

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

Лучший подход (ИМХО) - начинать с занятий изнутри, изменяя дизайн по ходу дела. Обычно я подхожу к этому, делая то, что я называю «инъекцией внутренней зависимости». Это включает в себя оставление сигнатур метода без изменений, но извлечение необходимых данных из зависимостей и затем извлечение функций, которые содержат действительную логику. Тривиальный пример может быть:

public int foo(A a, B b) {
  C c = a.getC();
  D d = b.getD();

  Bar bar = calculateBar(c, d);

  return calculateFoo(bar, this.baz);
}

Bar calculateBar(C c, D d) {
  ...
}

int calculateFoo(Bar bar, Baz baz) {
  ...
}

Теперь я могу написать тест для CalculateBar и CalculateBaz, но мне не нужно беспокоиться о настройке внутренних состояний (this.baz) и мне не нужно беспокоиться о создании фиктивных версий A и B.

После создания подобных тестов с существующими интерфейсами, я ищу возможность протолкнуть изменения в интерфейс, например, изменить метод Foo на C и D вместо A и B.

Что-нибудь из этого имеет смысл?

0 голосов
/ 06 декабря 2008

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

как следствие, издевательство требуется редко, но некоторые тесты охватывают несколько классов

0 голосов
/ 06 декабря 2008

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

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

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

Модульное тестирование повышает доверие ко мне как разработчику программного обеспечения.

0 голосов
/ 06 декабря 2008

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

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

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