Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Шаблоны прохода/сбоя

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

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

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

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

  • Шаблон Simple-Data-I/O
  • Шаблон ограничения ограничений
  • Обратный шаблон

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

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

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

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

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

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

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

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

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

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

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

  • Макет-шаблон объекта
  • Шаблон модели обслуживания
  • Шаблон моделирования битовой ошибки
  • Шаблон моделирования компонентов

Шаблоны многопоточности

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

  • Сигнальный шаблон
  • Шаблон разрешения блокировки

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

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

  • Шаблон тестирования на основе массива данных-данных
  • Шаблон тестирования ресурса-стресса
  • Образец теста загрузки

Шаблоны уровня представления

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

  • Шаблон проверки состояния просмотра
  • Модельный шаблон состояния

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

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

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

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

Ответ 7

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

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

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

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

Ответ 8

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

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

[TestFixture]
public class TestSomeUseCases() {

    // Service we want to test
    private TestableServiceImplementation service;

    // IoC-injected mock of service that 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 (или просто упорядочить) и реализовать оставшиеся абстрактные биты и тестовые функции в унаследованных классах, которые группируют тестовые функции.

Ответ 9

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