Полезные шаблоны проектирования для модульного тестирования / TDD? - PullRequest
44 голосов
/ 01 октября 2010

Чтение этот вопрос помог мне решить некоторые проблемы, которые у меня всегда были с юнит-тестированием, TDD и др.

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

Комментарии, такие как " Большая часть кода без модульных тестов создается с трудомзависимости (то есть новые везде) или статические методы. "и" ... нередко бывает высокий уровень связи между классами, трудно конфигурируемыми объектамивнутри вашего класса [...] и т. д. "заставили меня осознать, что следующим шагом является понимание того, как отсоединить код, чтобы сделать его тестируемым.

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

Ответы [ 9 ]

52 голосов
/ 07 января 2013

Здесь Майк Клифтон описывает 24 тестовых шаблона 2004 года. Это полезная эвристика при разработке модульных тестов.

http://www.codeproject.com/Articles/5772/Advanced-Unit-Test-Part-V-Unit-Test-Patterns

Паттерны Pass / Fail

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

  • Шаблон простого теста
  • Шаблон кода-пути
  • Шаблон диапазона параметров

Шаблоны транзакций данных

Шаблоны транзакций данных - это начало решения проблем сохранения данных и обмена данными. Больше на эту тему обсуждается в разделе «Модели симуляции». Также в этих шаблонах намеренно пропускаются стресс-тесты, например, загрузка на сервер. Это будет обсуждаться в разделе «Образцы стресс-теста».

  • Шаблон Simple-Data-I / O
  • Шаблон ограничения данных
  • Шаблон отката

Шаблоны управления коллекцией

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

  • Шаблон заказа-коллекции
  • Шаблон перечисления
  • Образец коллекции-ограничения
  • Шаблон индексации коллекции

Образцы исполнения

Модульное тестирование должно касаться не только функции, но и формы. Насколько эффективно тестируемый код выполняет свою функцию? Как быстро? Сколько памяти он использует? Эффективно ли компенсируется вставка данных для извлечения данных? Правильно ли высвобождает ресурсы? Все это входит в сферу юнит-тестирования. Включая шаблоны производительности в модульное тестирование, разработчик имеет цель достичь, что приводит к улучшению кода, улучшению приложения и более счастливому клиенту.

  • Образец теста производительности

Шаблоны процессов

Юнит-тестирование предназначено для проверки, ну, в общем, юнитов ... основных функций приложения. Можно утверждать, что процессы тестирования должны быть отнесены к процедурам приемочных испытаний, однако я не согласен с этим аргументом. Процесс - это просто другой тип устройства. Процессы тестирования с помощью модульного тестера предоставляют те же преимущества, что и другие модульные тесты - в нем документируется способ, которым должен работать процесс, и тестировщик может помочь исполнителю, выполняя также последовательное тестирование процесса, быстро выявляя потенциальные проблемы пользовательского интерфейса, такие как Что ж. Термин «процесс» также включает переходы состояний и бизнес-правила, которые должны быть проверены.

  • Шаблон последовательности процессов
  • Шаблон состояния процесса
  • Шаблон правил процесса

Моделирование

Транзакции данных сложно проверить, потому что они часто требуют предустановленной конфигурации, открытого соединения и / или онлайн-устройства (и многие другие). Поддельные объекты могут прийти на помощь, имитируя базу данных, веб-службу, пользовательское событие, соединение и / или аппаратное обеспечение, с которым выполняется код. У фиктивных объектов также есть возможность создавать условия отказа, которые очень трудно воспроизвести в реальном мире - соединение с потерями, медленный сервер, неисправный сетевой концентратор и т. Д.

  • Шаблон макета объекта
  • Шаблон сервис-симуляции
  • Шаблон симуляции битовых ошибок
  • Шаблон моделирования компонентов

Многопоточность

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

  • Сигнальный паттерн
  • Шаблон разрешения тупиковых ситуаций

Шаблоны для стресс-теста

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

  • Шаблон для массовых данных-стресс-тестов
  • Шаблон Resource-Stress-Test
  • Шаблон теста на нагрузку

Шаблоны слоев презентации

Одним из наиболее сложных аспектов модульного тестирования является проверка того, что информация поступает к пользователю прямо на самом уровне представления и что внутренняя работа приложения правильно устанавливает состояние уровня представления. Часто уровни представления связаны с бизнес-объектами, объектами данных и логикой управления. Если вы планируете модульное тестирование уровня представления, вы должны понимать, что четкое разделение задач является обязательным. Частью решения является разработка соответствующей архитектуры Model-View-Controller (MVC). Архитектура MVC предоставляет средства для разработки хороших методов проектирования при работе с уровнем представления. Однако этим легко злоупотреблять. Требуется определенная дисциплина, чтобы убедиться, что вы действительно правильно реализуете архитектуру MVC, а не просто одним словом.

  • Тестовый шаблон состояния просмотра
  • Тестовая таблица состояния модели
10 голосов
/ 01 октября 2010

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

  • Интерфейсы, интерфейсы, интерфейсы
  • внедрение зависимостей;это в сочетании с интерфейсами поможет вам менять части по желанию, чтобы изолировать модули, которые вы хотите протестировать.Вы хотите протестировать свою cron-подобную систему, которая отправляет уведомления другим сервисам?создайте его и замените реализацию реального кода на все остальное, используя компоненты, подчиняющиеся правильному интерфейсу, но жестко реагирующие так, как вы хотите протестировать: почтовое уведомление?проверить, что происходит, когда сервер smtp не работает, выдав исключение

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

7 голосов
/ 01 октября 2010

Книга Майкла Пера Эффективная работа с устаревшим кодом - это именно то, что вы ищете.Он определяет устаревший код как «код без тестов» и рассказывает о том, как его тестировать.

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

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

4 голосов
/ 11 февраля 2014

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

Вот некоторый гипотетический код C #, который демонстрирует шаблон.

[TestFixture]
public class TestSomeUseCases() {

    // Service we want to test
    private TestableServiceImplementation service;

    // IoC-injected mock of service that's needed for TestableServiceImplementation
    private Mock<ISomeService> dependencyMock;

    public void Arrange() {
        // Create a mock of auxiliary service
        dependencyMock = new Mock<ISomeService>();
        dependencyMock.Setup(s => s.GetFirstNumber(It.IsAny<int>)).Return(1);

        // Create a tested service and inject the mock instance
        service = new TestableServiceImplementation(dependencyMock.Object);
    }

    public void Act() {
        service.ProcessFirstNumber();
    }

    [SetUp]
    public void Setup() {
        Arrange();
        Act();
    }

    [Test]
    public void Assert_That_First_Number_Was_Processed() {
        dependencyMock.Verify(d => d.GetFirstNumber(It.IsAny<int>()), Times.Exactly(1));
    }
}

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

4 голосов
/ 01 октября 2010

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

Книга посвящена сафари, так что вы можете по-настоящему хорошо взглянуть на то, что внутри, и посмотреть, может ли это быть полезным: http://my.safaribooksonline.com/9780131495050

3 голосов
/ 01 октября 2010

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

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

Отлично! SOLID - это то, что вы ищете (да, действительно). Я продолжаю рекомендовать эти 2 электронные книги , особенно ту, которая посвящена SOLID, для рассматриваемой проблемы.

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

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

2 голосов
/ 01 октября 2010

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

1 голос
/ 01 октября 2010

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

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

Рекомендация такова: если очень сложно что-то протестировать, вы, вероятно, можете реорганизовать это в более мелкие проблемы и протестировать биты с рефакторингом изолированно. Поэтому, если у вас есть 200-строчный метод с 5 уровнями операторов if и несколькими циклами for, вы можете разбить этот присоски.

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

0 голосов
/ 05 октября 2010

Инъекция зависимости / IoC. Также ознакомьтесь с основами внедрения зависимостей, такими как SpringFramework и google-guice. Они также нацелены на то, как написать тестируемый код.

...