Лучшие практики тестовой разработки с использованием C# и RhinoMocks [закрыто]


чтобы помочь моей команде написать тестируемый код, я придумал этот простой список лучших практик для того, чтобы сделать нашу базу кода C# более тестируемой. (Некоторые из пунктов относятся к ограничениям Rhino Mocks, издевательской структуре для C#, но правила могут применяться и в более общем плане.) Есть ли у кого-нибудь лучшие практики, которым они следуют?

чтобы максимально повысить тестируемость кода, выполните следующие правила:

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

  2. классы проектирования с использованием инъекции зависимостей. причина: вы не можете издеваться или проверять то, что не видно.

  3. отделите код пользовательского интерфейса от его поведения с помощью Model-View-Controller или Model-View-Presenter. причина: позволяет тестировать бизнес-логику, в то время как части, которые не могут быть протестированы (пользовательский интерфейс) свернутый.

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

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

  6. изолировать внешние зависимости. причина: неразрешенные внешние зависимости не могут быть проверены.

  7. отметьте как виртуальные методы, которые вы собираетесь издеваться. причина: Rhino Mocks не может издеваться над невиртуальными методами.

7 85

7 ответов:

определенно хороший список. Вот несколько мыслей по этому поводу:

Сначала напишите тест, затем код.

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

классы проектирования с использованием зависимостей инъекция.

согласился. Когда объект создает свои собственные зависимости, вы не можете их контролировать. Инверсия инъекции управления / зависимости дает вам этот контроль, позволяя вам изолировать тестируемый объект с помощью mocks/stubs/etc. Вот как вы тестируете объекты в изоляции.

отделите код пользовательского интерфейса от его поведения с помощью Model-View-Controller или Model-View-Presenter.

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

не пишите статические методы или классы.

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

выключить программу интерфейсы, а не классы.

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

изолировать внешние зависимости.

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

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

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

и, несколько новых моментов, чтобы рассмотреть:

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

написать тесты с помощью Билл Уэйк устраивает/действует / утверждает технику. этот метод делает его очень ясным какая конфигурация необходима, что фактически испытывается, и что и ожидалось.

Не бойтесь свернуть свои собственные насмешки / окурки. часто, вы обнаружите, что использование среды mock-объектов позволяет тесты невероятно трудно читать. Свернув свой собственный, вы будете иметь полный контроль над своими насмешками/заглушками, и вы сможете сохранить свои тесты читаемыми. (Вернитесь к предыдущему пункту.)

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

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

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

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

// ShouldExpectMethodCallWithVariable
int value = 5;
var mock = new Mock<IFoo>();

mock.Expect(x => x.Duplicate(value)).Returns(() => value * 2);

Assert.AreEqual(value * 2, mock.Object.Duplicate(value));

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

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

Это очень полезный пост!

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

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

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

Я склонен верить, что Основное значение TDD находится в boundary (blackbox), а также в случайном тестировании whitebox критически важных областей системы.

реальная причина программирования против интерфейсов заключается не в том, чтобы облегчить жизнь носорога, а в том, чтобы прояснить отношения между объектами в коде. Интерфейс должен определять сервис, который необходим объекту из его среды. Класс предоставляет конкретную реализацию этой службы. Прочитайте книгу Ребекки Вирфс-Брок "дизайн объектов" о ролях, обязанностях и сотрудниках.

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

О, просто подумал о чем-то, что я делаю, что Вы тоже можете захотеть. Я вообще есть библиотека модульных тестов с тестовым приспособлением для каждой политики классов, где каждый тест переходит в соответствующее пространство имен. У меня также есть другая библиотека тестов (интеграционные тесты?), который находится в более BDD style. Это позволяет мне писать тесты, чтобы определить, что должен делать метод, а также то, что приложение должно делать в целом.

вот еще один, который я думал о том, что мне нравится делать.

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

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