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

Обсудим три базовых подхода к тестированию чего‑либо в программе:

1. Тестирование наблюдаемого поведения (по принципу чёрного ящика)

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

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

2. Тестирование состояния

Бывает такое, что вызываемый нами объект мутирует состояние внепроцессной зависимости, например, базы данных. В таком случае тестируемый объект не вернёт нам достаточно данных для оценки его работы, так как его наблюдаемое поведение скрыто от клиента.

Это приводит к тому, что мы начинаем использовать детали реализации БД в тесте. В данном случае это знания о диалекте базы данных, названиях таблиц, столбцов их типов и т. п. Эти данные могут претерпеть изменения со временем.

Что делать, чтобы улучшить положение? Во многих случаях можно отдать предпочтение другим методам тестируемого объекта (как один из вариантов), и тогда детали реализации в тесте снова станут неизвестны.

3. Проверка поведения

Самыми хрупкими тестами являются тесты, которые проверяют:

  • Сколько раз был вызван метод?

  • Какие параметры были переданы в то или иное место?

  • В какой последовательности были произведены вызовы?

  • и т. п.

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

  • Протестировать класс Client, что мы отправили корректные данные в «сеть»

  • «Высечь в камне» сложный алгоритм/бизнес‑процесс, который не должен меняться

  • Зафиксировать контракт с внепроцессной зависимостью

  • В большинстве других случаев стоит избегать таких тестов

Во второй части мы более подробно разберём юнит‑тесты, и в миллионный раз сравним две школы юнит‑тестирования.

Комментарии (6)


  1. TITnet
    24.09.2024 20:28
    +1

    Тестирование состояния
    Во многих случаях можно отдать предпочтение другим методам тестируемого объекта(как один из вариантов), и тогда детали реализации в тесте снова станут неизвестны.

    Каким другим? Если верить рисунку, то вы предлагаете изменить поведение сервера, чтобы он на запрос стал отдавать некоторый статус записи в БД. Т. е. раньше клиент дёргает сервер, тот что-то пишет в БД и тест проверял запись в БД. Это понятный сценарий и только так и можно быть уверенным, что сервер сделал то, что от него ожидали. Вы же предлагаете изменить поведение сервера в угоду удобства тестирования? Или я вас неправильно понял?


    1. KarmanovichDev Автор
      24.09.2024 20:28

      Есть такой подход, когда мы проверяем состояние не с помощью деталей реализации, а с помощью уже имеющегося открытого API.

      • Вместо того, чтобы явно вызывать orm или sql запрос, чтобы проверить, что вы создали нужный объект, в тесте вам нужно дёрнуть метод get того же репозитория.

      • Этот подход при желании можно использовать даже при тестировании самого приложения. Сначала вы делаете test_client.save(path=..., ...), а на этапе проверки делаете test_client.get(path=..., ...)

      Не совсем понял про "менять сервер в угоду тестов"


  1. saymon_says
    24.09.2024 20:28

    Если тест работал, а потом начал падать, значит тест работает. Кто-то влез в логику и сломал ее.


    1. KarmanovichDev Автор
      24.09.2024 20:28

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


      1. saymon_says
        24.09.2024 20:28

        Это не хрупкий, а просто кривой тест. Какие-то параметры входящие возможно криво сделаны для теста. Что чаще всего у нас и происходит, потому что в каждом тесте идёт генерация данных, а не хардкорный какие-то из файла.


        1. KarmanovichDev Автор
          24.09.2024 20:28

          Я говорю про ситуацию, когда результат не меняется, а объект работает и возвращает нужный результат, но тест падает.