Обновить
0
0

Пользователь

Отправить сообщение
  1. Билд можно ускорить, в конце концов можно просто параллелить запуск.

  2. Во-первых, это можно поправить. Во-вторых, это же тест, он независимый и быстрый - запустил в его дебаге и посмотрел

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

  1. А может быть и так - на плохой код написаны тесты и теперь мы не можем этот плохой код переделать в хороший, т.к все тесты просто сломаются и будем вечно жить с плохим кодом. Вообще почему мы тут говорим о написании тестов на код, мы же хотим TDD, сначала тесты писать, а потом код? Перемудренная логика - это требование бизнеса. Ее можно и нужно упрощать, но это не всегда возможно. А обычно в бизнес логике и есть ценность it-продукта.

  2. Либо проект в активной разработке и постоянно обрастает функционалом

  3. Юнит тест отдельного метода - с точки зрения документации кода не много информации приносит. Мы же пишем понятный код с короткими методами, стараемся соблюдать single layer of abstraction и прочее. Чтобы понять, что метод делает должно быть проще сам метод посмотреть. А общую картину юнит тест на отдельный метод - не дает.

  4. Рефакторить отдельный метод? Если рефакторить что - то серьезное, то тут только интеграционные тесты могут регресс поймать, а то и e2e. После рефакторинга у нас половина юнит-тестов будет пытаться несуществующие методы вызывать.

  5. Тут тоже самое - если метод реально сложный - то ок, юнит тест необходим. Но считать, что по юнитам можно понять как работает фича - это странно на мой взгляд. А то будет ситуация, что замок на двери зарыли, а саму дверь захлопнуть забыли. Хотя оба теста на замок и дверь отлично работают. А в реальности фича, это не 2 составные части, а 50.

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

Если проект относительно сложный и живой - это не будет работать. Если вы напишите на каждый метод по 20 тестов на каждый инвариант использования, а потом прилетит требование от бизнеса поменять логику так, что этот метод надо вообще будет удалить / объединить с другим методом, хотя в целом контракт внешне не сильно поменялся - то что делать с этими тестами? Удалить только.

А интеграционный тест - вы поправили пару полей в тестовых данных, пару проверок на границе фичи (внешние вызовы, очередь, БД и др.) и все - тест работает и регресс проверяет. Внутри меняйте и двигайте код как угодно.

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

Если честно, не согласен и считаю, что всё должно быть наоборот.

Основное поведение системы должно покрываться интеграционными тестами. А юнит-тесты стоит писать выборочно — там, где в одном методе или классе действительно сосредоточено много логики, или же для утилитных методов, какие-то сложно-читаемые штуки с регулярными выражениями и подобными вещами.

Аргументы следующие:

  1. В большинстве проектов мы стараемся писать простые и читаемые методы. Тест на каждый из них — это гонка за покрытием без реальной пользы. Чем меньший объём логики покрывает тест, тем выше риск, что он упустит общий смысл поведения фичи/системы.

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

  3. TDD в такой интерпретации почти невозможен. Тут почти всегда будет 2 варианта:

    1. Логика фичи настолько простая, что мы заранее можем разбить всё на методы, написать на них тесты, а потом реализовать — но тогда и тесты несут мало пользы - всё и так очевидно.

    2. Логика фичи сложная — и тогда мы не сможем заранее угадать нужную декомпозицию. Придётся писать код, рефакторить его в пару итераций, а потом уже писать тесты. Это уже не TDD, да и такие тесты в любом случае не проверяют фичу в целом.

  4. Медленные интеграционные тесты — почти всегда решаемая задача. Есть способы ускорить их запуск: поднимать только необходимый контекст, переиспользовать контекст / БД / контейнеры, использовать ленивую загрузку и прочее. Данные можно подготовить заранее и один раз, и например, миграции БД не накатывать на каждый тест. Миграции тестировать отдельными тестами, если они очень долгие. В общем, варианты есть.

  5. Сложность подготовки тестовых данных — это тоже сигнал. Если мы не хотим писать интеграционные тесты, т.к не можем под них создать тестовые данные - значит система переусложнена. Тут уже вопрос - что мы вообще собираемся тестировать и какой смысл любых тестов на такой системе? Тут надо архитектурно декомпозировать систему, упрощать и так далее. Все-таки тестовые данные почти всегда создать можно, возможно чуть больше усилий нужно потратить, но это окупиться тем, что теперь у нас будут тесты, которые наконец-то дадут вам возможность использовать их для рефакторинга, регресса и прочее.

Итого, если есть возможность, то я бы рекомендовал делать 90% именно интеграционных тестов.

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность