Test-Driven Development (TDD) — это техника, которая требует, чтобы вы сначала написали тест, прежде чем приступать к реализации решения. Хотя разработчики используют эту методику и в целом во время разработки, есть способ применять ее только для исправления ошибок.
Обнаружение ошибки и так может разочаровать, но обнаружение ошибки, которая повторно возникла, будет еще хуже. Предотвратить повторное появление ошибки после ее устранения — важнейший навык разработчиков.
Что такое разработка, управляемая тестами (TDD)?
Разработка через тестирование (TDD), требует, чтобы вы написали неудачный тест до начала реализации решения. С его помощью можно определить все спецификации новой функции и убедиться, что вы не забыли ни о каких ожидаемых результатах.
Например, представьте, что у вас есть следующая структура для статьи:
struct Article { let title: String let author: String let link: URL }
Возможно, мы захотим создать новое вычисляемое свойство, которое будет возвращать домен блога для этой статьи. Прежде чем приступить к написанию фактического вычисляемого свойства, мы определим следующий тестовый пример:
func testArticleDomain() { let article = Article( title: "Async await in Swift explained with code examples", author: "Antoine van der Lee", link: URL(string: "https://www.avanderlee.com/swift/async-await/")! ) XCTAssertEqual(article.blogDomain, "avanderlee.com") }
Этот код не скомпилируется, поскольку свойство blogDomain
не существует. Поскольку мы хотим, чтобы тест сначала провалился, мы можем добавить вычисляемое свойство, которое возвращает пустую строку:
extension Article { var blogDomain: String { "" } }
Теперь мы можем успешно запустить модульный тест и сделать вывод, что он действительно не работает:
Наконец, мы реализуем фактическую логику и повторно запустим тест, чтобы убедиться в его успешности:
extension Article { var blogDomain: String { link.host()?.replacingOccurrences(of: "www.", with: "") ?? "" } }
Рабочий процесс похож на то, что делают многие разработчики, но главное отличие заключается в том, что вы начинаете с написания тестов, а не переходите непосредственно к разработке функций.
Преимущества TDD
Разработчики, как правило, не решаются начать использовать разработку через тестирование в своем рабочем процессе. Им кажется, что писать неудачные тесты — это лишнее и пустая трата времени. Прежде чем я начну перечислять преимущества TDD, думаю, важно подчеркнуть, что вы можете использовать эту технику как дополнительный набор инструментов, когда она подходит для решения ваших текущих задач.
Я использую ее время от времени, когда хочу очистить свой разум от ожидаемых результатов. Написав тесты, вы гарантируете, что запомните все крайние случаи и ожидаемые результаты. Во-вторых, вы сможете полностью сосредоточиться на разработке решения, не думая постоянно о результатах, которые вы должны поддерживать: вы можете запускать тесты и знать, что вы закончили, когда все они успешны.
Еще одно преимущество написания сначала неудачных тестов — это гарантия того, что ваш тест действительно не сработает. Это звучит глупо, но я видел много тестов, которые всегда срабатывали, даже если реализация менялась. Другими словами, тест не мог поймать ни одной неправильной реализации.
И наконец, начав с тестов, вы убедитесь, что ваш новый код будет тестируемым с самого начала. Когда вы пишете новый код без тестов в голове, написание тестов впоследствии, скорее всего, будет более сложным. Поскольку это более сложно, для вас становится проще вообще пропустить написание тестов, что приводит к снижению тестового покрытия.
Win-win в решении ошибок с помощью тестов
Основная причина, по которой я начал писать о разработке, управляемой тестами, заключается в том, что я использую ее в основном при решении ошибок.
Воспроизведение ошибки с помощью тестов вместо ручного вмешательства
Когда я начинаю решать проблему, я прежде всего хочу знать, как ее воспроизвести. Первое, что вы можете сделать, это открыть приложение и начать перемещаться по нему. Однако, по моему опыту, гораздо проще посмотреть на конкретный код и написать тест с аналогичными входными данными, как указано в сообщении об ошибке. В идеале у вас должно быть достаточно логов (например, с помощью Diagnostics), чтобы понять, в чем причина ошибки. Если нет, можно прочитать конкретные строки кода и с помощью теста найти триггер.
Дополнительным преимуществом написания теста является то, что вы, скорее всего, лучше поймете причину ошибки. Не удивлюсь, если вы также сможете быстрее решить проблему. Поэтому TDD отлично работает вместе с исправлением ошибок.
Решение ошибки с помощью теста
После того как тест создан, можно приступать к исправлению ошибки. В зависимости от ошибки, это может быть сложно и отнимать много времени. Наличие способа быстрой проверки решения может значительно сократить время на исправление ошибки. Вместо того чтобы вручную выполнять всевозможные действия, вы можете просто повторно запустить тест и проверить его.
Я видел разработчиков, решающих проблемы с помощью ручного взаимодействия с приложением, когда они даже не могли постоянно воспроизводить ошибку. Другими словами, если повезет, вы думаете, что решили проблему, а на самом деле это не так. Очень важно иметь постоянное воспроизведение, прежде чем считать исправление надежным.
Большее покрытие кода и больше уверенности
Решив проблему, вы одновременно внедрили новый тест и увеличили покрытие кода. Вы также можете быть более уверены в своей кодовой базе, поскольку убедились, что ошибка не может вернуться, не пройдя тест. Уверенность в кодовой базе нельзя недооценивать, она крайне важна для приложений, которые хотят регулярно выпускать обновления для большой аудитории.
Заключение
Разработка, управляемая тестами — это отличная техника, позволяющая увеличить покрытие кода тестами и одновременно повысить качество кода. Поначалу писать неудачные тесты может быть утомительно, но в результате вы получите более полную реализацию функции, которая охватывает все ожидаемые результаты. Если использовать тесты в сочетании с исправлением ошибок, вы повысите свою уверенность и будете уверены, что ошибка не вернется в будущем.
Спасибо!