4.5.2. Блочные тесты

Блочное тестирование наиболее понятно для программиста. Фактически это тестирование методов какого-то класса программы в изоляции от остальной программы и является комбинацией методов «белого» и «черного» ящиков.

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

Чтобы гарантировать тестируемость, можно применять методологию TDD, которая предписывает сначала писать тест, а потом код реализации тестируемого метода. Тогда архитектура получается тестируемой. Распутывание зависимостей можно осуществить с помощью Инспектора Зависимостей (Dependency Injection, Microsoft). Тогда каждой зависимости явно сопоставляется интерфейс и явно определяется, как инжектируется зависимость — в конструктор, в свойство или в метод.

Для осуществления блочного тестирования существуют специальные API и фреймворки. Например, NUnit или тестовый фреймфорк из среды Visual Studio. Для возможности тестирования классов в изоляции существуют специальные «Mock» фреймворки. Например «Rhino Mocks». Они позволяют по интерфейсам автоматически создавать заглушки для классов-зависимостей, задавая у них требуемое поведение.

По блочному тестированию написано много статей [15–20]. Ниже приводятся основные идеи и концепции методологий блочного тестирования.

Основные аспекты при проектировании блочных тестов:

    • Влияние тестов на дизайн (API),тест — первый клиент разрабатываемого API.
  1. Тесты как документация.
  2. Как часто нужно запускать тесты?
  3. Когда добавлять тесты:
    • при разработке контракта класса;
    • при обнаружении ошибки.
  4. Как изменять тесты при рефакторинге?
    • это помогает найти проблемы, с которыми столкнутся клиенты.
  5. Полнота тестирования:
    • стремиться к полным тестам;
    • сосредоточиться на проблемных режимах;
    • проверять реакции на нарушение контракта (исключения и коды ошибок).
  6. Что невозможно протестировать:
    • утверждения;
    • приемочные тесты.

Методология JUnit

  • Класс тестов TestCase.
  • testMethod().
  • Методы assertTrue(), assertFalse(), assertEquals(), assertNull(), assertNotNull(), assertSame().
  • Метод fail(), тестирование исключений.
  • setUp(), fixture.
  • tearDown(), external fixture.
  1. TestSuite, JUnit 4, TestNG, использование аннотаций зависимости между тестами.

Методология TDD (Test Driven Development)

  1. Связь с экстремальным программированием.
  2. Чистый код, который работает.
  3. Сначала пишутся тесты, потом код:
    • заказ API от клиента;
    • сначала подумайте, потом напишите;
    • документация контракта;
    • уверенность в изменениях.
  4. Цикл TDD:
    • красный;
    • зеленый;
    • рефакторинг.
  5. Пять шагов:
    • написание теста, компиляция;
    • красная полоса;
    • модификация;
    • зеленая полоса;
    • устранение дублирования.
  6. Действия на каждом шаге.

Методика TDD.

  1. Написав тест, сделать минимум действий, необходимых для компиляции.
  2. Удостовериться: что не должно работать, не работает. Если работает — разберитесь, почему.
  3. Минимальная модификация. Если из-за вашей модификации приходится писать новый тест, значит она слишком большая:
    • подделка реализации;
    • тестирование теста.
  4. Необходимо добиться прохождения теста перед тем, как писать новый код (тест).
  5. Устранение дублирования во всем: в коде, константах, тестах.
  6. Влияние TDD на дизайн:
    • Тест — это спецификация;
    • Выявление проблем и задач;
    • Дублирование где бы то ни было — повод для рефакторинга.
    • зеленая полоса;
    • устранение дублирования.

Основные паттерны TDD:

  1. Изолировать тесты
  2. Список тестов – список задач
  3. Вначале пишется тест
  4. Начать тест с assert
  5. Понятные тестовые данные
  6. Когда надо писать новый тест, выбирать из списка тот, который:
    • можно написать;
    • будет полезен для понимания задач на данном этапе.
  7. Объясняющий тест
  8. Тест для изучения библиотеки
  9. Любая посторонняя мысль – повод для добавления строки в список тестов.
  10. Нашли ошибку – пишем тест, который ее воспроизводит
  11. Если тест слишком велик, разделите его на части
  12. Поддельные объекты: если нужно тестировать что-то очень сложное и неуправляемое (например, пользовательский интерфейс), можно подделать (имитировать) это своим тестовым классом.