Лучшие практики тестовой разработки с использованием C# и RhinoMocks [закрыто]
чтобы помочь моей команде написать тестируемый код, я придумал этот простой список лучших практик для того, чтобы сделать нашу базу кода C# более тестируемой. (Некоторые из пунктов относятся к ограничениям Rhino Mocks, издевательской структуре для C#, но правила могут применяться и в более общем плане.) Есть ли у кого-нибудь лучшие практики, которым они следуют?
чтобы максимально повысить тестируемость кода, выполните следующие правила:
Сначала напишите тест, затем код. причина: это гарантирует, что вы пишите тестируемый код и что каждая строка кода получает тесты, написанные для него.
классы проектирования с использованием инъекции зависимостей. причина: вы не можете издеваться или проверять то, что не видно.
отделите код пользовательского интерфейса от его поведения с помощью Model-View-Controller или Model-View-Presenter. причина: позволяет тестировать бизнес-логику, в то время как части, которые не могут быть протестированы (пользовательский интерфейс) свернутый.
Не пишите статические методы или классы. причина: статические методы трудно или невозможно изолировать и Носорог издевается не может издеваться над ними.
программа отключает интерфейсы, а не классы. причина: использование интерфейсов проясняет отношения между объектами. Интерфейс должен определять сервис, который необходим объекту из его среды. Кроме того, интерфейсы можно легко высмеивать с помощью Rhino Mocks и другие издевательские рамки.
изолировать внешние зависимости. причина: неразрешенные внешние зависимости не могут быть проверены.
отметьте как виртуальные методы, которые вы собираетесь издеваться. причина: Rhino Mocks не может издеваться над невиртуальными методами.
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 может на самом деле сделать для вас).
кроме того, мне всегда нравится иметь проект детской площадки, открытый для тестирование битов кода и идей, с которыми я не знаком. Это не должно быть проверено в системе управления версиями. Еще лучше, он должен быть в отдельном репозитории управления версиями только на машине разработчика.