Модульные тесты проверяют работоспособность каждого компонента. Они чрезвычайно полезны при поиске дефектов, близких к моменту их создания, что значительно сокращает затраты на их устранение и значительно уменьшает количество дефектов, которые в конечном итоге возникают в вашем выпуске. Кроме того, хорошие юнит-тесты делают рефакторинг намного проще и надежнее.
Интеграционные тесты (или «веб-» тесты в данном случае) также очень важны, но представляют собой более позднюю линию защиты, чем модульные тесты. Одиночный интеграционный тест охватывает такой огромный объем кода, что при его сбое требуется много исследований для определения дефекта (или, возможно, группы дефектов), вызвавшего сбой. Это дорого, особенно когда вы пытаетесь протестировать сборку релиза, чтобы получить ее за дверью. Это еще более затратно, учитывая, что вероятность появления ошибки с исправлением в среднем довольно высока, а вероятность того, что ошибка блокирует дальнейшее тестирование релиза (что чрезвычайно дорого для цикла разработки).
Напротив, когда модульный тест не пройден, вы точно знаете, где находится дефектный код, и вы обычно точно знаете, что код делает неправильно. Кроме того, ошибка модульного теста должна воздействовать только на одного разработчика за раз и должна быть исправлена до того, как код будет зарегистрирован.
Исправлять ошибки всегда дороже, чем раньше. Всегда.
Подумайте о создании автомобиля. Вы бы подождали, пока весь автомобиль сойдет с конвейера, чтобы проверить, работает ли каждый компонент? В этот момент, если вы обнаружите, что проигрыватель компакт-дисков, или двигатель, или кондиционер, или круиз-контроль не работают, вы должны вывести из строя весь автомобиль, устранить проблему, а затем повторно протестировать все (что, надеюсь, не выявить любые новые дефекты). Это, очевидно, неправильный способ сделать это, точно так же, как и попытка выпускать программное обеспечение во время тестирования только в том случае, если оно работает в конце процесса, а не на каждом важном этапе по пути с нуля.