Каноничный TDD и список тестов

Каноничный TDD и список тестов #

TDD (Test Driven Development) — это процесс написания кода через тестирование.

Это полностью меняет процесс написания кода:

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

Процесс #

Процесс написания кода по TDD выглядит так:

---
config:
  flowchart:
    defaultRenderer: "elk"
---
flowchart LR
    TestList(Список
        тестов)
    subgraph цикл Red-Green-Refactor
        Red(Падающий
        тест)
        Green(Пройденный
            тест)
        Refactor(Рефакторинг)
    end
    CheckTestList{Остались
        тесты?}
    End((Конец))

    TestList --> Red
    Red --> Green
    Green --> Refactor
    Refactor --> CheckTestList
    CheckTestList -->|да|Red
    CheckTestList -->|нет|End

    style Red fill:#FFCCCC,stroke:#FF0000
    style Green fill:#CCFFCC,stroke:#66CC66
    style Refactor fill:#CCFFFF,stroke:#66FFFF

Формат списка тестов #

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

  • Список тестов следует расположить в проекте тестов — например, tests/Lexer.UnitTests
  • Файл следует назвать TESTLIST.md.
  • Тесты описываются кратко в формате TODO-списка: - [ ] ваш текст
  • Пройденные тесты обозначаются латинской буквой “x”: - [x] ваш текст

Описание пунктов в списке тестов может быть произвольным — важно лишь помнить, что список тестов напоминает о том, какие тесты уже написаны и какие предстоит написать.

Пример списка тестов #

Пример оформления TESTLIST.md:

# Список тестов

## Класс Lexer

- [x] Разбор SELECT без FROM: `SELECT 2025;`
- [x] Разбор FROM: `SELECT first_name FROM student;`
- [ ] Поддержка множественных полей: `SELECT first_name, last_name, email FROM student;`
- [ ] Определение ключевых слов без учёта регистра: `select first_name, last_name FrOM student;`
- [ ] Оператор сложения: `SELECT count + 1 FROM counter;`

Цикл Red, Green, Refactor #

Тесты из списка тестов реализуются в цикличном процессе с шагами Red, Green, Refactor:

  1. (Red) Напишите один тест из списка тестов
    • старайтесь выбирать тест, который даёт новую информацию
    • старайтесь не выбирать тест, для реализации которого нужно совершить много работы и принять много решений
    • тест пишется до создания/изменения интерфейса тестируемого класса
    • тест должен падать при выполнении либо вовсе не компилироваться (если указанные в нём символы из тестируемого кода ещё не объявлены)
  2. (Green) Реализуйте сценарий теста
    • можно провести мелкий рефакторинг до реализации
    • следуйте минимализму
    • если в голову пришли новые идеи — запишите их в список тестов
    • добейтесь прохождения теста
  3. (Refactor) Проведите рефакторинг
    • можно пропустить этот шаг
    • после рефакторинга тесты должны оставаться зелёными
  4. Если в списке тестов остались тесты — повторите цикл, начиная с шага №1 (Red).