Единственный тест, который я пишу

Dec 04 2022
В инженерном мире почти постоянно ведутся разговоры о том, какие виды тестов лучше; модульные тесты, интеграционные тесты, сквозные тесты и так далее. Некоторое время назад я решил, что буду писать только один вид теста.

В инженерном мире почти постоянно ведутся разговоры о том, какие виды тестов лучше; модульные тесты, интеграционные тесты, сквозные тесты и так далее.

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

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

Вот принципы, которым я следую:

  1. Я не пишу ни одного теста, пока у меня не будет определен четкий общедоступный интерфейс.
  2. Мои тесты должны максимально точно имитировать поведение реального пользователя . Это означает вызов только общедоступного API или, если это внешний интерфейс, разработанный для конечного пользователя, выполнение только того, что сделал бы конечный пользователь.
  3. Если функция или компонент не являются частью общедоступного интерфейса, я не тестирую их напрямую. Если невозможно вызвать его косвенно через какой-либо общедоступный путь, какова его цель?
  4. Никаких удаленных сетевых вызовов. Если это не вызов localhost (например, локальная тестовая база данных), то его необходимо имитировать. Мои тесты должны последовательно проходить без подключения к сети или Интернету.
  5. Никаких насмешек над внутренними путями кода. Мокать на границе сети — это здорово, но имитировать функции или API, которые существуют в кодовой базе, которую я тестирую, нельзя.
  6. Никакое состояние не переносилось в разные тесты. Если тест опирается на состояние из предыдущего теста или может каким-либо образом повлиять на это состояние, что-то пошло не так. Это не обязательно должно означать «очистить все состояние после каждого теста».
  7. Нет тестирования внутреннего состояния. Если мне нужно инициализировать или настроить какое-то внутреннее состояние вручную в моем тесте (без использования другого существующего общедоступного интерфейса), мой тест, вероятно, не будет хорошим.
  8. Нет тестирования деталей внутренней реализации. Если рефакторинг моего кода приведет к провалу теста, вероятно, это плохой тест.
  9. Никаких «модульных тестов», которые вызывают внутренние функции. Если я чувствую сильное желание протестировать подобные функции, их, вероятно, следует заранее разбить на отдельные автономные модули или пакеты с четким интерфейсом, полностью отделенным от какой-либо моей бизнес-логики.
  10. Никаких сквозных тестов, требующих запуска полного сервера и базы данных и нескольких служб и запуска их всех вместе, если только это не крайне целесообразно делать на моем локальном хосте.
  11. Я сосредотачиваюсь на «охвате вариантов использования», а не «охвате строк кода».
  12. Сначала напишите тест, если заранее ясно, как будет выглядеть публичный интерфейс. В противном случае сначала напишите код, а затем протестируйте его.
  13. Я нарушаю любое из приведенных выше правил, когда это лучше сделать, чем не писать тест или оставить вариант использования непроверенным.