Erhalten Sie Zugang zu diesem und mehr als 300000 Büchern ab EUR 5,99 monatlich.
Автоматизированное тестирование — залог стабильной разработки качественных приложений. Полноценное тестирование должно охватывать отдельные функции, проверять интеграцию разных частей вашего кода и обеспечивать корректность с точки зрения пользователя. Книга научит вас быстро и уверенно создавать надежное программное обеспечение. Вы узнаете, как реализовать план автоматизированного тестирования для JavaScript-приложений. В издании описываются стратегии тестирования, обсуждаются полезные инструменты и библиотеки, а также объясняется, как развивать культуру, ориентированную на качество. Вы исследуете подходы к тестированию как серверных, так и клиентских приложений, а также научитесь проверять свое программное обеспечение быстрее и надежнее.
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 565
Veröffentlichungsjahr: 2024
Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:
Переводчик С. Черников
Лукас да Коста
Тестирование JavaScript. — СПб.: Питер, 2023.
ISBN 978-5-4461-3913-2
© ООО Издательство "Питер", 2023
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.
В память о моей бабушке Марли Тейшейре да Коста, которая всегда делала все возможное для того, чтобы я достиг успеха.
«Тестирование JavaScript» — книга о тестировании, которую я хотел бы иметь у себя под рукой шесть лет назад. В то время я был стажером отдела обеспечения качества (quality assurance, QA) — приобретал свой первый опыт в индустрии программного обеспечения (ПО). К сожалению, от меня не требовалось того, что я любил больше всего: колдовать на клавиатуре. Вместо этого мне приходилось просматривать большое количество информации, нажимать кнопки, заполнять формы и следить за тем, чтобы программное обеспечение, которое мы создавали, работало как следует.
«Наверняка можно придумать что-то получше», — думал я. Поэтому и начал изобретать способы переложить всю рутинную работу на компьютеры, чтобы в освободившееся время совершенствовать свои творческие навыки.
Спустя 18 месяцев мне показалось, что с этой задачей я в основном справился. К тому времени я автоматизировал свои обязанности по обеспечению качества и превратился в разработчика ПО.
Как только я начал писать приложения, у меня появилось еще больше вопросов. Работая в сфере QA довольно продолжительное время, я не хотел зависеть от других в создании работающего программного обеспечения. Но и возвращаться к заполнению форм и щелканью по кнопкам, жертвуя драгоценным временем, отведенным для творчества, мне также не хотелось.
И снова я подумал, что «должен быть способ получше». Именно тогда я начал больше читать о тестировании. Теперь, когда мне был доступен исходный код, я обнаружил, что могу создавать программное обеспечение более уверенно и за меньшее время. Кроме того, могу освободить своих товарищей по QA для выполнения более творческой работы, вместо того чтобы перебрасывать им код для ручного тестирования.
Сложнее всего было найти нужную информацию. Иногда в интернете попадались полезные статьи, но большинство из них уже устарели или освещали какую-то одну небольшую часть процесса.
Собрать фрагментарные знания в единое целое стало для меня самым трудным делом. Всегда ли разработчикам следует писать тесты? Если да, то какие, для чего и в каких количествах? Как разработка программного обеспечения и QA дополняют друг друга?
В те годы у нас не было единого источника с ответами на все вопросы. Книги, которую я хотел прочитать, не существовало. Поэтому я решил ее написать.
И хотя по интернету разбросано много хорошего материала, большая часть из того, что мне хотелось видеть, попросту отсутствовала. Авторы библиотек тестирования, предназначенных для всеобщего использования, так и не структурировали процесс написания и применения тестов.
Эта книга объединяет в себе разные фрагменты информации в доступной форме. Здесь я собрал то, чему мне удалось научиться за годы чтения и профессиональной работы, а также то, что я открыл для себя, занимаясь поддержкой библиотек тестирования, таких как Chai и Sinon, которыми пользуются миллионы.
Я уверен, что надежные методы тестирования являются залогом успеха для любого программного проекта, так как помогают писать более качественное ПО за меньшее время и с меньшими денежными затратами. Самое главное — они освобождают нас, людей, от рутинной работы и позволяют заниматься тем, что у нас получается лучше всего — созданием программ, — а это для меня по-прежнему сродни магии.
Мамин будильник, как и мой, всегда срабатывает до шести утра. Не знаю, как без этого мне удалось бы написать около 500 страниц, которые вам предстоит прочитать: большая часть из них писалась, пока все еще спали. Мама научила меня ценить дисциплину и тяжелый труд, за что я ей крайне признателен.
Вместе с ней благодарности заслуживают и многие другие люди: за помощь и преподанные мне уроки.
В первую очередь я хотел бы поблагодарить свою семью, которая подбадривала меня с другого берега Атлантического океана: моего отца Эрсилиу, обещавшего всегда поддерживать меня, сестру Луизу, самого доброго человека из всех, кого я знаю, мою маму Патрицию, чей тяжелый труд я превознес в самом первом абзаце.
Помимо них, я должен поблагодарить бабушку и дедушку: они присматривали за мной, пока родители были на работе. Особое спасибо бабушке Марли Тейшейре да Коста, которой я посвятил эту книгу.
Какой бы трудной ни была наша жизнь в Бразилии, бабушка всегда старалась создать мне все условия для работы, от книг до компьютеров. В рабочие дни она готовила мне обед и разрешала ночевать в ее доме рядом с университетом, чтобы я мог получше отдохнуть и быть более внимательным на занятиях.
Помимо моей семьи, есть еще несколько людей, без которых я не смог бы закончить эту работу: Дуглас Мело и Лоренцо Гариботти показали мне, что такое настоящая дружба, а Ана Зардо — что мир больше, чем я думал; Алекс Монк, мой психотерапевт, помог сориентироваться в изменчивой жизни и совладать с моими частыми экзистенциальными кризисами; Гидеон Фаррелл когда-то пригласил меня в Лондон и продолжает доверять сейчас, помогая мне демонстрировать свои лучшие профессиональные качества.
Не могу не поблагодарить всех участников сообщества открытого кода на JavaScript за все, чему они меня научили за эти годы: Лукаса Виейру, моего приятеля по колледжу, одного из самых талантливых известных мне инженеров; Карла-Эрика Копсенга, который пригласил меня в проект Sinon.js и с которым мне посчастливилось работать в 2017 году; Кита Сиркела, предложившего мне стать основным разработчиком Chai.js, — он всегда был надежным другом и помог удержаться на плаву, когда я переехал в Англию три года назад. Я рад, что интернет связал меня с такими замечательными людьми!
Хочу сказать спасибо всем рецензентам: Серджио Арбео, Джереми Чен, Джузеппе Де Марко, Лучиану Энаке, Фостеру Хайнсу, Джампьеру Гранателле, Ли Хардингу, Джоанне Купис, Чарльзу Ламу, Бонни Малеку, Брайану Милеру, Барнаби Норману, Прабхути Пракашу, Деннису Рейлу, Сатейю Саху, Лизе Сесслер, Раулю Сайлсу, Эзре Симелоффу, Денизу Вехби, Ричарду Б. Уорду и Родни Уэйсу. Ваши советы помогли сделать эту книгу лучше!
В завершение хотел бы поблагодарить моих редакторов и сотрудников издательства Manning Хелен Стергиус, Денниса Селлингера и Шрихари Шридхарана за то, что вычитали каждую страницу и терпеливо отвечали на многочисленные вопросы, которые у меня возникали в процессе.
Obrigado.
Книга на практических примерах научит вас тестировать код на языке JavaScript и расскажет, что необходимо учитывать при принятии решения о том, какие тесты и когда следует писать.
Помимо обзора наиболее популярных средств тестирования для JavaScript и рекомендуемых методов написания тестов, в книге вы найдете информацию, как тесты разных типов дополняют друг друга и как их можно внедрить в процесс разработки. Все это поможет создать лучшее ПО за меньшее время, с меньшим количеством ошибок и с большей уверенностью в его качестве.
Книга «Тестирование JavaScript» в основном написана для младших разработчиков и для инженеров в сфере программного обеспечения, которым кажется, что «должен существовать лучший способ» создания рабочего ПО, но которые еще не знают, как это сделать.
Предполагается, что читатели уже умеют писать код, однако никаких предварительных знаний о тестировании программного обеспечения не требуется.
В дополнение к практическим аспектам написания тестов в книге объясняется, почему тестирование играет важную роль и как оно влияет на разрабатываемые проекты, что позволит принимать оптимальные решения в вашем контексте.
Эта книга состоит из 12 глав, сгруппированных в три части.
В части I объясняется, что такое автоматизированные тесты, почему они важны, на какие типы делятся и как каждый из типов влияет на проекты.
• В главе 1 речь идет о том, что такое автоматизированные тесты и какую пользу приносит их написание.
• В главе 2 перечисляются различные типы автоматизированных тестов, а также преимущества и недостатки каждого из них. Вы узнаете, на что следует обращать внимание при принятии решения о написании теста. Здесь также представлены основополагающие шаблоны проектирования, которые можно применять к тестам любого рода.
В части II приводятся конкретные примеры, чтобы вы научились писать разные типы тестов из первой части.
• Глава 3 охватывает методы тестирования, которые помогают сделать тесты максимально эффективными. Здесь вы узнаете, как группировать тесты в наборы для получения точных результатов, как писать более совершенные утверждения, чтобы отлавливать больше ошибок, и какие части вашего кода следует изолировать на время тестирования. Кроме того, в этой главе объясняется, что такое покрытие кода, как его измерить и насколько обманчивым иногда бывает данный показатель.
• В главе 4 показано, как писать тесты для серверных приложений. Здесь говорится об основных факторах, которые необходимо учитывать, чтобы сделать приложение тестируемым, обсуждается тестирование маршрутов сервера и его промежуточного слоя, а также демонстрируется, что делать с внешними зависимостями наподобие баз данных или сторонних API.
• В главе 5 представлены методы, которые должны помочь удешевить тесты для серверного кода, сделать их более быстрыми и надежными. В этой связи вы узнаете, как избавляться от непредсказуемых тестов, как выполнять тесты параллельно и как избегать их дублирования.
• В главе 6 описывается процесс тестирования стандартного клиентского приложения на JavaScript. Здесь вы узнаете, как симулировать браузерное окружение внутри своей платформы тестирования и как писать тесты, которые взаимодействуют с интерфейсом приложения, обращаются к API браузера и работают с протоколами HTTP и WebSocket.
• Глава 7 посвящена экосистеме тестирования React: в ней объясняется, как работают тесты для приложений React. Материал главы опирается на то, что вы уже усвоили в предыдущих главах. Здесь дается краткий обзор разных инструментов, которые можно использовать для тестирования приложений React, и демонстрируется, как начать писать тесты для кода на основе данной библиотеки. Дополнительно вы получите советы о том, как применять похожие методики к другим библиотекам и платформам на языке JavaScript.
• В главе 8 более подробно рассматриваются практические аспекты тестирования приложений React. Я объясняю, как тестировать компоненты, взаимодействующие друг с другом, как тестировать стили компонента, что такое тестирование снимков и как определить, следует его применять или нет. Вы также узнаете о важности приемочного тестирования на уровне компонентов и о том, как оно может помочь в создании более качественных приложений React за меньшее время.
• В главе 9 речь идет о разработке через тестирование (test-driven development, TDD). Вы узнаете, как применять этот метод разработки ПО, чем полезно его внедрение и когда его следует применять. Помимо практических аспектов TDD, мы обсудим то, как данный подход влияет на команды разработчиков и как создать условия для его успешного использования. Здесь также рассматривается связь TDD с методом под названием «разработка через поведение», который может улучшить взаимопонимание между заинтересованными сторонами и повысить качество программного обеспечения.
• В главе 10 описываются сквозные тесты на основе пользовательского интерфейса и их роль в проекте. Здесь вы узнаете, чем этот тип тестов отличается от других и как определить, когда их следует писать.
• Глава 11 посвящена практическим аспектам тестов на основе пользовательского интерфейса. Вы напишете свои первые сквозные тесты на основе пользовательского интерфейса, научитесь делать их надежными и устойчивыми к изменениям, а также узнаете, как выполнять их в разных браузерах. Кроме того, здесь объясняется, как внедрить в тесты визуальное регрессионное тестирование и чем этот новый вид тестов может быть полезен.
Часть III охватывает дополнительные методы, позволяющие усилить положительное влияние тестов на проект.
• В главе 12 описываются непрерывные интеграция и доставка и объясняется, как они могут пригодиться. Здесь также перечисляются основные факты, которые следует знать, чтобы применять эти методики в проектах.
• В главе 13 обсуждаются технологии, инструменты и методы, которые дополняют тесты. Здесь вы узнаете, как система типов помогает отлавливать ошибки и делает ваши тесты более эффективными, как обзор кода повышает его качество и какую роль в создании рабочего ПО играют документация и мониторинг. Здесь также показано, как сделать процесс отладки кода более быстрым и надежным.
Советую прочитать три первые главы последовательно и уже потом переходить к остальному тексту. В первых главах изложены основополагающие концепции тестирования и то, как они соотносятся друг с другом. Очень важно, чтобы чтение начиналось с этого материала, так как без него вы не сможете извлечь максимальную пользу из последующих глав.
Дальше можете переходить к любой интересующей вас главе, в зависимости от того, какого рода ПО вы собираетесь тестировать.
К главам 12 и 13 в идеале следует переходить только тогда, когда вы уже подготовили все необходимые тесты и хотите понять, как дополнить свои методики и инфраструктуру тестирования.
Книга содержит множество практических примеров. Все они доступны онлайн в репозитории книги на GitHub, который читатели могут найти по адресу https://github.com/lucasfcosta/testing-javascript-applications. В репозитории примеры разделены по главам — у каждой главы своя папка. Внутри папок примеры сгруппированы по разделам.
Внутристрочный код и отдельные листинги отформатированы с использованием такогомоноширинногошрифта, чтобы его можно было отличить от обычного текста. Если код изменился по сравнению с предыдущими шагами в той же главе (например, при появлении чего-то нового в имеющейся строчке кода), он выделен жирным шрифтом.
Зачастую оригинальный исходный код переформатирован: мы добавили переводы строк и переделали отступы, чтобы лучше использовать место на страницах печатного издания. Кроме того, когда код описывается в тексте, из него обычно убираются комментарии. Многие листинги содержат примечания, акцентирующие внимание на важных идеях.
Я предусмотрел примечания для всех существенных примеров, чтобы выделить важные участки и объяснить читателям, что делает каждый фрагмент кода.
Коды представленных здесь примеров также доступны для загрузки на сайте Manning по адресу www.manning.com/books/testing-javascript-applications.
Все примеры кода в этой книге были написаны и проверены в macOS Catalina. Тем не менее они должны работать на любых платформах, включая Linux и Windows.
Единственные изменения, которые могут потребоваться, связаны с тем, как устанавливаются переменные окружения в вашей конкретной командной оболочке и операционной системе. Например, если вы используете PowerShell на компьютере с Windows, вы не можете установить значение переменной окружения, указав ИМЯ_ПЕРЕМЕННОЙ=значение перед командой.
Для выполнения примеров на вашем компьютере должны быть установлены Node.js и NPM. Эти два пакета обычно поставляются вместе. При установке Node.js вы, как правило, получаете NPM в придачу. Чтобы загрузить и установить оба программных компонента, можете воспользоваться инструкциями на странице https://nodejs.org/ru/download/. При создании примеров использовались Node.js 12.18 и NPM 6.14.
Ваши замечания, предложения, вопросы отправляйте по адресу [email protected] (издательство «Питер», компьютерная редакция).
Мы будем рады узнать ваше мнение!
На веб-сайте издательства www.piter.com вы найдете подробную информацию о наших книгах.
Лукас да Коста — разработчик программного обеспечения, автор статей и известный спикер. Являясь активным участником опенсорс-сообщества, он входит в число основных разработчиков двух популярнейших библиотек тестирования для JavaScript: Chai и Sinon. Кроме того, он внес свой вклад в развитие множества других проектов, включая Jest и NodeSchool.
За последние несколько лет Лукас выступал на многочисленных конференциях по разработке ПО более чем в десяти странах.
Его презентации переведены энтузиастами на многие языки, включая русский, китайский, французский, португальский и испанский, и используются по всему миру в качестве справочного пособия во множестве курсов по программированию.
Лукасу нравятся книги, красивый код, командная строка и Vim. На самом деле его любовь к Vim настолько сильна, что у него на щиколотке есть татуировка с командой :w.
Изображение на обложке называется Bourgeois de Paris («Буржуа Парижа»). Иллюстрация позаимствована из книги Costumes civils de actuals de toue les peuples connus («Гражданские костюмы всех известных народов мира»), опубликованной во Франции в 1788 году, — коллекции костюмов Жака Грассе де Сен-Совера (1757—1810). Каждая гравюра тщательно нарисована и раскрашена от руки. Богатое разнообразие этой коллекции служит ярким напоминанием о том, насколько разнились культуры городков и регионов мира всего 200 лет назад. Изолированные друг от друга, люди разговаривали на разных диалектах и языках. Будь то городские улицы или сельская местность, место жительства человека и его ремесло вместе с положением в обществе легко можно было определить по одежде.
С тех пор мы начали одеваться по-другому, а региональные отличия, которые в то время были такими значимыми, постепенно сошли на нет. В наши дни зачастую бывает сложно отличить друг от друга жителей разных континентов, не говоря уже о разных городах, регионах или странах. Возможно, взамен культурного многообразия мы получили более разнообразную личную жизнь и уж точно более разнообразную и динамичную ее технологическую составляющую.
В то время как большинство компьютерных изданий сложно отличить друг от друга, компания Manning выбирает для своих книг обложки, основанные на богатом региональном разнообразии, которое Грассе де Сен-Совер воплотил в своих иллюстрациях два столетия назад. Это ода находчивости и инициативности современной компьютерной индустрии.
Что бы вы ни разрабатывали — сайт для кондитерской своего дяди или платформу для торговли ценными бумагами, самой важной характеристикой вашего кода является его работоспособность. Клиенты дяди, несомненно, будут активнее заказывать его творожные десерты, если вы создадите понятный и красиво оформленный сайт. Точно так же брокеры на Уолл-стрит смогут больше заработать, если у вашей платформы будут высокая скорость и быстрая реакция. Тем не менее пользователи попросту проигнорируют все ваши усилия, направленные на производительность и внешний вид, если код окажется ненадежным.
Если программа не работает, то неважно, насколько она быстрая и красивая. В конечном счете детям хочется больше сладкого, а брокерам хочется работать с бˆольшим количеством акций. Ни те ни другие не хотят «больше программного обеспечения».
В части I объясняется, как автоматизированные тесты помогают давать людям то, чего они хотят: программное обеспечение, которое работает. Кроме того, здесь вы научитесь доставлять ПО с большей надежностью и за меньшее время.
В главе 1 я расскажу о том, что такое автоматизированные тесты и чем они могут помочь вам и вашей команде.
В главе 2 представлено несколько типов автоматизированных тестов. В ней вы узнаете, когда следует использовать тот или иной тип тестирования и какие у каждого из типов преимущества и недостатки. Вы также изучите основополагающие методы, которые будут применяться на протяжении всей книги.
В этой главе
• Что такое автоматизированный тест.
• Для чего пишутся автоматизированные тесты.
• Как автоматизированные тесты могут помочь в написании лучшего кода за меньшее время и с большей уверенностью.
Когда программное обеспечение пронизывает все вокруг, от кондитерской вашего дяди до экономики вашей страны, спрос на новые возможности растет экспоненциально. Тем большую важность приобретает частая доставка рабочего кода — желательно по нескольку раз в день. Именно для этого нужны автоматизированные тесты. Уже давно прошли те времена, когда программисты могли позволить себе вручную и нерегулярно тестировать код. В наши дни написание тестов — это не просто рекомендуемый подход, а отраслевой стандарт. Если прямо сейчас поискать актуальные вакансии, то почти все они требуют той или иной степени осведомленности об автоматизированном тестировании ПО.
Неважно, сколько у вас клиентов и с какими объемами данных вы имеете дело. Написание эффективных тестов является полезной практикой для компаний любого масштаба, от гигантов Кремниевой долины, имеющих венчурный капитал, до индивидуального стартапа, который вы недавно запустили. Тесты способствуют общению между разработчиками и помогают избегать ошибок, поэтому их рекомендуется применять в проектах любых размеров. Чем больше разработчиков занимаются проектом и чем выше цена неудачи, тем важнее наличие тестов.
Книга «Тестирование JavaScript» нацелена на профессионалов, уже умеющих писать программное обеспечение, но еще не знающих, как писать тесты или почему это так важно. При работе над книгой я ориентировался на людей, которые или только что окончили курсы программирования, или недавно начали карьеру программиста и хотят профессионально расти. Я рассчитываю, что читатели знают основы JavaScript и понимают такие концепции, как объекты Promise и функции обратного вызова. Не обязательно быть специалистом в JavaScript — достаточно уметь писать программы, которые работают. Если все сходится и вы заинтересованы в создании самого ценного вида ПО — работающего, то эта книга для вас.
Данный материал не предназначен для профессионалов в области обеспечения качества или нетехнических руководителей: темы разбираются с точки зрения разработчика и акцент делается на использовании результатов тестирования для написания более качественного кода за меньшее время. Я не стану рассказывать о том, как проводить ручное или исследовательское тестирование. Здесь вы также не найдете информации об оформлении отчетов об ошибках или управлении рабочими процессами тестирования. Эти задачи пока что нет возможности автоматизировать. Если хотите узнать о них больше, советую поискать книгу, предназначенную для тех, кто работает в сфере QA.
Основным инструментом, который мы будем использовать, является Jest. Вы овладеете им в ходе написания рабочих автоматизированных тестов для нескольких небольших приложений. Приложения будут написаны как на чистом JavaScript, так и с использованием популярных библиотек, таких как Express и React. Предварительный опыт с Express и особенно с React будет полезен, но краткого знакомства с этими инструментами тоже достаточно. Все примеры я буду разрабатывать с нуля, требуя от вас как можно меньше предварительных знаний, поэтому советую учиться на ходу и не готовиться заранее.
В главе 1 мы пройдемся по концепциям, лежащим в основе всех последующих примеров. Как показывает мой опыт, самая главная причина написания плохих тестов связана с непониманием того, что они собой представляют и какие задачи перед ними можно и нужно ставить. Именно с этого мы и начнем.
Разобравшись с тем, что такое тесты и для чего их пишут, мы обсудим разные ситуации, в которых написание тестов может способствовать как написанию более качественного ПО за меньшее время, так и взаимодействию между разработчиками. Эти основополагающие идеи будут играть ключевую роль в главе 2, когда мы начнем писать первые тесты.
У дяди Луиса не было ни единого шанса преуспеть в Нью-Йорке, а вот в Лондоне он стал известен своими ванильными творожными десертами. Ввиду их необычайной популярности дядя Луис быстро понял, что управление кондитерской с помощью ручки и бумаги уже не отвечает масштабам продаж. Чтобы поспевать за растущим спросом, он нанял лучшего известного ему программиста (вас) и поручил создать интернет-магазин.
Требования были простыми: у клиентов должна быть возможность заказывать кондитерские изделия, вводить адрес доставки и оплачивать заказы по интернету. Выполнив поставленную задачу, вы решили убедиться в том, что магазин работает как следует. Вы создали базы данных (БД), наполнили их тестовой информацией, запустили сервер и открыли созданный сайт у себя на компьютере. Попытавшись заказать парочку пирожных, вы обнаружили ошибку: например, заметили, что в корзину покупок можно добавить только одну единицу какого-либо товара.
Если бы эта ошибка осталась в готовом сайте, дядя Луис столкнулся бы с огромными проблемами. Таким образом, вы решили, что возможность добавления нескольких единиц товара всегда нужно проверять.
Вы могли бы вручную тестировать каждую версию, как делалось когда-то в старых сборочных цехах. Но такой подход не масштабируется: он занимает слишком много времени и, как это свойственно любым ручным процессам, чреват ошибками. Чтобы можно было решить проблему, вместо вас роль покупателя должен играть код.
Подумаем, как пользователь сообщает программе о том, что в корзину нужно что-то добавить. Это упражнение поможет определить, какие этапы последовательности действий необходимо заменить автоматизированными тестами.
Пользователи взаимодействуют с вашим приложением через сайт, который шлет HTTP-запрос на сервер. Запрос информирует функцию addToCart о том, какой товар и в каком количестве нужно добавить в корзину. Корзина покупателя идентифицируется по сеансу отправителя. После добавления товара в корзину сайт обновляется в соответствии с ответом сервера. Этот процесс показан на рис. 1.1.
Рис. 1.1. Последовательность действий при создании заказа
ПРИМЕЧАНИЕ
f(x) — это просто обозначение функций, которое будет использоваться в схемах. Оно ничего не говорит о том, какие у функции параметры.
Заменим покупателя программным кодом, способным вызывать функцию addToCartFunction. Таким образом, вам не нужно будет полагаться на то, что кто-то вручную добавит товар в корзину, чтобы потом проверить ответ: у вас будет фрагмент кода, выполняющий проверку. Это и есть автоматизированный тест.
автоматизированный ТЕСТ
Автоматизированные тесты — программы, которые автоматизируют процесс тестирования ПО. Они взаимодействуют с вашим приложением для выполнения каких-то действий и затем сравнивают полученный результат с ожидаемым выводом, определенным заранее.
Код вашего теста создает корзину покупок и просит функцию addToCart добавить в нее товары. Затем тест проверяет, присутствуют ли в полученном ответе запрошенные элементы (рис. 1.2).
Рис. 1.2. Последовательность действий для тестирования addToCart
В тесте можно смоделировать ситуацию, в которой пользователи смогут добавить в корзину всего одно миндальное пирожное.
1. Создайте экземпляр корзины.
2. Вызовите функцию addToCart и укажите ей добавить в корзину миндальное пирожное.
3. Проверьте, есть ли в корзине два миндальных пирожных.
Заставив тест воспроизвести шаги, которые ранее привели к ошибке, вы можете доказать, что этой конкретной ошибки больше не происходит.
Теперь напишите тест, гарантирующий, что в корзину можно добавить больше одного миндального пирожного: он будет создавать собственный экземпляр корзины и использовать функцию addToCart для того, чтобы добавить в нее два миндальных пирожных. После вызова функции addToCart тест проверит содержимое корзины: если оно соответствует ожиданиям, значит, все работает правильно. Это позволит вам удостовериться в том, что в корзину можно добавить два миндальных пирожных (рис. 1.3).
Теперь, когда клиенты, как и положено, могут купить столько миндальных пирожных, сколько пожелают, представьте, что вы пытаетесь смоделировать покупку клиентом 10 000 миндальных пирожных. К вашему удивлению, заказ без проблем проходит. Однако у дяди Луиса нет в наличии такого количества пирожных! Его кондитерская еще небольшая и не в состоянии выполнять огромные заказы в короткие сроки. Чтобы вовремя доставлять безупречные десерты всем желающим, Луис просит вас дать клиентам возможность заказывать только то, что есть в наличии.
Рис. 1.3. Последовательность действий для теста, который проверяет, можно ли добавить в корзину несколько миндальных пирожных
Для определения того, какую часть последовательности действий нужно заменить автоматизированными тестами, подумайте, что должно происходить, когда клиенты добавляют товары в свои корзины, и соответствующим образом адаптируйте приложение.
Когда покупатель нажимает на сайте кнопку Добавить в корзину, как показано на рис. 1.4, клиентский код должен отправить серверу HTTP-запрос с указанием добавить в корзину 10 000 миндальных пирожных. Прежде чем выполнить просьбу, серверу нужно свериться с базой данных и убедиться в том, что товар имеется в наличии в достаточном количестве. Если количество имеющихся пирожных не меньше числа, указанного в запросе, товар добавляется в корзину и сервер возвращает ответ клиентскому коду, который обновляется соответствующим образом.
ПРИМЕЧАНИЕ
Для тестирования следует использовать отдельную базу данных. Не засоряйте свою производственную базу тестовой информацией.
Тесты добавляют и изменяют всевозможные данные, что может привести к их потере или к несогласованности содержимого БД.
Применение отдельной базы данных также упрощает поиск первопричины программной ошибки. Поскольку вы полностью контролируете состояние БД, действия клиентов не будут искажать результаты ваших тестов.
Рис. 1.4. Желаемая последовательность действий для добавления в корзину только доступных товаров
Эта ошибка еще критичнее, поэтому следует проявить повышенную бдительность. Для большей уверенности в тесте его можно написать еще до фактического исправления ошибки, чтобы увидеть, когда он работает не так, как вы того ожидаете.
Тест можно считать полезным только в том случае, если он проваливается, когда ваше приложение не работает.
Данный тест работает по тому же принципу, что и предыдущий: заменяет пользователя программным кодом и имитирует его действия. Разница в том, что здесь необходимо предусмотреть дополнительный шаг для удаления всех миндальных пирожных из списка имеющихся в наличии. Тест должен подготовить подходящие условия и смоделировать действия, которые приводят к проявлению ошибки (рис. 1.5).
Рис. 1.5. Необходимые шаги теста, проверяющего, можно ли добавить в корзину товары, которые уже закончились
Наличие такого теста помогает быстрее устранить дефект. При внесении любого изменения тест будет сигнализировать о том, исправлена ли ошибка. Вам не нужно самостоятельно заходить в базу данных, удалять все миндальные пирожные, открывать сайт и пытаться добавить их в свою корзину: тест сделает это намного быстрее.
Поскольку вы уже написали тест для проверки возможности добавления покупателем нескольких единиц товара в корзину, он предупредит вас при повторном возникновении ошибки из-за внесенных исправлений. Тесты предоставляют быструю обратную связь и укрепляют вашу уверенность в том, что ПО действительно работает.
Но должен предупредить: автоматизированные тесты не гарантируют создания работающего ПО. Тесты не могут доказать, что ПО работает, — они могут доказать только обратное. Если бы при добавлении в корзину 10 001 миндального пирожного наличие товара по-прежнему игнорировалось, вы бы могли об этом узнать только после проверки этого конкретного ввода.
Тесты подобны экспериментам. Свои ожидания от того, как должно работать программное обеспечение, вы кодируете в тесты и хотите верить, что если ранее они отрабатывали без заминки, то и дальше приложение будет вести себя подобным образом. Но это не всегда так. Чем больше у вас тестов, тем лучше они имитируют поведение настоящих пользователей, тем больше гарантий вы получаете.
Автоматизированные тесты при этом не избавляют от необходимости ручного тестирования. Проверка кода от имени конечного пользователя и проведение исследовательского тестирования по-прежнему незаменимы. Поскольку книга ориентирована на разработчиков ПО, а не на тестировщиков, в контексте этой главы я буду называть ненужный процесс ручного тестирования, который часто выполняется во время разработки, просто ручным тестированием.
Такие тесты важны тем, что дают быструю и безотказную обратную связь. Мы детально обсудим, как своевременный и точный отклик улучшает процесс разработки ПО, делая его единообразным и предсказуемым. Это позволяет легко воспроизводить проблемы и документировать тестовые случаи, что упрощает совместную работу внутри команды (или разных команд) и сокращает время, необходимое для создания высококачественных программных продуктов.
Наличие предсказуемого процесса разработки позволяет избежать ситуации, когда реализация какой-то функциональной возможности или исправление ошибки приводят к непредвиденному поведению. Уменьшение количества сюрпризов, возникающих в ходе разработки, облегчает оценку стоящих перед вами задач и позволяет не так часто переписывать код.
Чтобы вручную проверить работоспособность всего программного продукта, требуется много времени, и это чревато ошибками. Тесты оптимизируют процесс, сокращая время получения отклика о коде, над которым вы работаете, и ускоряя тем самым исправление ошибок. Чем меньше задержка между написанием кода и получением обратной связи, тем более предсказуемой становится разработка.
Чтобы проиллюстрировать, как именно тесты делают разработку более предсказуемой, представим, что дядя Луис попросил вас дать клиентам возможность отслеживать состояние заказов. Это позволило бы ему уделять больше времени приготовлению сладостей, вместо того чтобы отвечать на звонки и уверять клиентов в том, что их заказ будет доставлен вовремя. Луис увлекается творожными десертами, а не телефонными переговорами.
Если бы вы реализовали функцию отслеживания без автоматизированных тестов, вам пришлось бы вручную пройти весь процесс покупки и убедиться в том, что он работает (рис. 1.6). И при этом каждый раз вам нужно было бы не только перезагружать сервер, но также очищать базы данных, чтобы гарантировать их согласованность, открывать браузер, добавлять товары в корзину, указывать время доставки, проходить процедуру оплаты. И только после всего этого у вас была бы возможность проверить, отслеживается ли ваш заказ.
Но, чтобы протестировать эту функцию даже вручную, она должна быть доступна на сайте. Вам нужно написать для нее интерфейс и довольно существенную часть серверного кода, с которым будет взаимодействовать клиент.
Рис. 1.6. Этапы проверки отслеживания заказа
Ввиду отсутствия автоматизированных тестов вам придется написать довольно много кода, прежде чем вы сможете проверить, работает ли данная функция. Если внесение каждого изменения сопряжено с длительным и утомительным процессом, это подталкивает к написанию более крупных фрагментов кода. Что, в свою очередь, задерживает получение обратной связи и может привести даже к тому, что вы получите ее слишком поздно. К тому же, когда увеличивается объем написанного кода, увеличивается и количество потенциальных ошибок. В какой из тысяч новых строчек кода скрывается ошибка, которую вы только что наблюдали?
Рис. 1.7. Тесты для функции trackOrder могут вызывать ее напрямую, поэтому вам не нужно трогать другие части приложения
Автоматизированный тест наподобие показанного на рис. 1.7 позволяет получить обратную связь после написания меньшего количества кода. Такие тесты могут вызывать функцию trackOrder напрямую, что позволяет убедиться в ее работоспособности без необходимости трогать другие части приложения.
Когда тест проваливается после написания десяти строк кода, вам нужно волноваться только об этих десяти строках. Даже если дефект находится в другом месте, вам будет намного проще определить, что спровоцировало нежелательное поведение.
Ситуация может усугубиться, если вы нарушите работу других частей приложения. Обнаружив ошибки в процедуре оплаты, вам придется проверить, как на нее повлияли ваши изменения. Чем больше изменений вы вносите, тем сложнее определить, в чем проблема.
Автоматизированные тесты, такие как на рис. 1.8, могут сразу же оповестить о проблеме, что поможет вам принять необходимые меры. Частое выполнение тестов даст точную информацию о том, какие участки приложения сломались, непосредственно в момент поломки. Помните, что чем меньше времени вам придется ждать обратной связи после написания кода, тем более предсказуемым будет процесс разработки.
Я часто вижу, как разработчикам приходится выбрасывать свой код из-за того, что в него было внесено слишком много изменений за один раз. Когда изменения приводят к поломке множества разных частей приложения, разработчики не знают, за что хвататься. Им проще начать с чистого листа, чем разбираться с беспорядком, который они устроили. Сколько раз вы оказывались в подобной ситуации?
Рис. 1.8. Автоматизированные тесты могут проверять участки вашего кода по отдельности, предоставляя точные сведения о том, что сломалось, непосредственно в момент поломки
Чем больше шагов у задачи, тем выше вероятность того, что человек допустит ошибки при их выполнении. Автоматизированные тесты упрощают и ускоряют воспроизведение ошибок и их устранение.
Перед тем как отслеживать свой заказ, покупатель должен пройти через несколько этапов: добавить товар в корзину, выбрать дату доставки и оплатить. Чтобы протестировать приложение и убедиться в том, что оно будет работать для клиентов, вы должны проделать то же самое. Процесс достаточно длинный, чреватый ошибками, с большим количеством вариантов выполнения каждого шага. Автоматизированные тесты позволяют гарантировать, что эти шаги будут выполняться строго и безошибочно.
Представьте, что при тестировании приложения вы выявили ошибку: например, клиент может перейти к оплате с пустой корзиной или недействительной банковской картой. Для обнаружения этих ошибок вам придется выполнить последовательность действий вручную.
Чтобы предотвратить повторение ошибок, вы должны в точности воспроизвести те шаги, которые к ним привели. Если список тестовых случаев становится слишком длинным или у вас получается слишком много шагов, человеческий фактор даст о себе знать. Ошибки непременно закрадутся в ваш код (рис. 1.9), если только у вас нет перечня действий, которому вы всегда неукоснительно следуете.
Рис. 1.9. Шаги, которые нужно выполнять при тестировании каждой функциональной возможности
Вряд ли вы забудете проверить процесс заказа торта, но что, если тортов будет –1 или NaN? Людям свойственно что-то упускать из виду и ошибаться, поэтому программное обеспечение и сбоит. Человек должен заниматься теми вещами, которые у него хорошо получаются, а выполнение рутинных повторяющихся задач в их число не входит.
Даже решив вести учет всех тестовых случаев, вы должны будете прилагать дополнительные усилия для поддержания списка в актуальном состоянии. А если когда-нибудь вы забудете его обновить и с приложением произойдет что-то не отмеченное в списке, то чья это будет вина — приложения или документации?
Автоматизированные тесты выполняют одни и те же действия каждый раз, когда вы их запускаете. Компьютер, выполняющий тесты, не пропустит никаких шагов и не совершит ошибки.
Все, кто пробовал пирог баноффи в исполнении Луиса, знают, что Луис вполне мог бы претендовать на победу в телешоу Great British Bake Off. Если вы создадите правильное ПО, однажды, возможно, кондитерские Луиса откроются по всему миру, от Сан-Франциско до Санкт-Петербурга. Но в этом случае одного разработчика будет недостаточно.
Если вы наймете других разработчиков для совместной работы, у вас внезапно появятся и новые разнообразные проблемы. Представьте, что вы, к примеру, реализуете новую систему скидок, а Элис в это время занимается механизмом генерации купонов. Как быть, если изменения, внесенные вами в процедуру оплаты, сделают невозможным применение купонов к заказам? Иными словами, как гарантировать, что ваша работа не вступит в конфликт с работой Элис и наоборот?
Если первой свои функции в кодовую базу включит Элис, вам придется спрашивать, как протестировать ее часть работы, чтобы ничего не сломать. Таким образом, включение вашего кода отнимет время как у вас, так и у Элис.
Но усилиями, которые вы с Элис приложили для ручного тестирования изменений, дело не ограничится. Вам еще придется вместе поработать над интеграцией вашего и ее кода, а потом и проверить, как эти изменения интегрировались (рис. 1.10).
Этот процесс не только трудоемкий, но и подверженный ошибкам. Вы должны помнить все шаги и все крайние случаи, которые нужно протестировать как в вашем коде, так и в коде Элис. Но мало того, что шаги нужно помнить, — их еще необходимо точно выполнить.
Рис. 1.10. Ручное тестирование требует проверки изменений на каждом этапе процесса разработки
Когда программист добавляет для своих функций автоматизированные тесты, от этого выигрывают все. Если для кода Элис есть тесты, вам не нужно просить ее, чтобы она проверяла свои изменения. Во время слияния обеих частей кода можно просто запустить имеющиеся автоматизированные тесты, вместо того чтобы снова проходить через весь процесс ручного тестирования.
Даже если ваши изменения основаны на изменениях, внесенных Элис, тесты будут служить актуальной документацией, на которую можно ориентироваться в дальнейшей работе. Хорошо написанные тесты — это лучшая документация, которая только может быть у разработчика. Они должны успешно выполняться, поэтому их актуальность гарантирована. Если вы все равно будете писать техническую документацию, почему бы вместо нее не создать тест?
При интеграции вашего кода с тем, что написала Элис, вам также нужно будет добавить автоматизированные тесты, проверяющие эту интеграцию. Новые тесты будут использоваться последующими разработчиками при реализации функциональных возможностей, имеющих отношение к вашему коду, и это сэкономит им время. Написание тестов при внесении каких-либо изменений порождает эффективный цикл взаимодействия, когда каждый разработчик помогает тем, кто будет работать с кодовой базой после него (рис. 1.11).
Этот подход оптимизирует совместную работу, но не устраняет необходимость в общении, которое лежит в основе любого успешного проекта. Автоматизированные тесты в значительной мере улучшают процесс взаимодействия между разработчиками и в сочетании с другими методиками, такими как обзор кода, делают его еще более эффективным.
Рис. 1.11. Усилия, необходимые для проверки изменений на каждом этапе процесса разработки в случае наличия автоматизированных тестов
Одна из самых сложных задач в сфере проектирования ПО — организация эффективной совместной работы нескольких разработчиков. Тесты в этом деле являются крайне полезным инструментом.
Дяде Луису все равно, какой язык вы используете, и уж точно его не заботит, сколько тестов вы написали. Он хочет продавать выпечку, торты и прочие сладкие шедевры. Его также заботит доход. Если для удовлетворения клиентов и повышения выручки требуются новые функции, он хотел бы, чтобы вы реализовали их как можно скорее. Но с одной оговоркой: эти функции должны работать.
С коммерческой точки зрения важны не сами тесты, а скорость и корректность кода. В предыдущих разделах мы говорили о том, как тесты улучшают процесс разработки, делая его более предсказуемым, воспроизводимым и дружественным к совместной работе. Однако, по большому счету, все эти преимущества ценны лишь потому, что с их помощью можно получить более качественное ПО за меньшее время.
Когда написание кода, его проверка на отсутствие определенных дефектов и его интеграция с кодом других разработчиков требуют меньше времени, это делает вашу компанию более успешной. То же самое можно сказать о предотвращении регрессий и повышении безопасности процесса развертывания.
Тесты требуют определенных затрат, ведь для их написания нужно время. Но они все равно нужны, так как их преимущества существенно перевешивают недостатки.
Изначально написание теста может занять много времени, даже больше, чем тестирование вручную. Но чем чаще он выполняется, тем больше пользы он приносит. Например, ручная проверка может занять одну минуту, а написание автоматизированного теста — пять минут, но после пятого выполнения этот тест себя окупит. И поверьте мне, выполнений у теста будет куда больше пяти.
Если сравнивать с ручным тестированием, которое всегда занимает одно и то же время (или больше), время и усилия, необходимые для выполнения автоматизированного теста, сводятся почти к нулю. Объем работы при ручном тестировании растет намного быстрее. Это различие в усилиях, необходимых для написания автоматизированных тестов и проведения тестирования вручную, проиллюстрировано на рис. 1.12.
Рис. 1.12. Ручное и автоматизированное тестирование: сравнение прилагаемых усилий с течением времени
Написание тестов подобно покупке акций. В самом начале вы можете заплатить высокую цену, но потом будете получать дивиденды на протяжении долгого времени. Как и в финансовой области, дело, в которое лучше инвестировать (и стоит ли это делать вообще), зависит от срока, который вы наметили для получения своих денег обратно. Наиболее выгодны тесты для долгосрочных проектов. Чем дольше развивается проект, тем больше усилий удается сэкономить и тем больше внимания можно уделить разработке новых возможностей или другим конструктивным задачам. А вот краткосрочным проектам, как те, которые пишутся на коленке на хакатонах, это не сильно поможет: их время жизни слишком короткое для того, чтобы сэкономить усилия за счет тестирования.
В последний раз, когда Луис спросил, могли бы вы реализовывать новые функции быстрее, если бы не писали столько тестов, вы уже не говорили о финансах — воспользовались другой аналогией. Вы сказали ему, что это было бы сродни повышению температуры в печи для ускоренного приготовления пирога: корочка бы подгорела, а внутри все осталось бы сырым.
• Автоматизированные тесты — это программы, автоматизирующие процесс тестирования программного обеспечения. Они взаимодействуют с вашим приложением и сравнивают фактический вывод с ожидаемым. Если вывод правильный, они выполняются успешно, если нет, вы получаете содержательное объяснение.
• Тесты, которые никогда не проваливаются, бесполезны. Теряется их суть, состоящая в том, что они должны проваливаться, когда приложение ведет себя не так, как нужно.
• Тот факт, что ваше ПО работает, не может быть доказан: вы можете доказать лишь наличие дефектов. Тесты показывают отсутствие определенных ошибок, но не гарантируют, что ошибок нет совсем. Вашему приложению можно передавать почти бесконечное количество входных значений, но протестировать их все невозможно. Тесты обычно ищут дефекты, которые встречались прежде, или отслеживают определенного рода ситуации, в которых код должен работать.
• Автоматизированные тесты сокращают задержку между написанием кода и получением обратной связи, делая тем самым процесс разработки более упорядоченным и избавляя от многих сюрпризов. Когда процесс разработки предсказуем, разработчику легче оценивать задачи, в результате чего нет необходимости часто пересматривать код.
• Автоматизированные тесты всегда выполняют одну и ту же последовательность шагов. Они ничего не забывают и не допускают ошибок. Они в точности повторяют тестовые случаи и упрощают воспроизведение дефектов.
• Когда тесты автоматизированы, переписывание кода происходит реже, а взаимодействие становится более эффективным. Разработчики могут самостоятельно проверить корректность чужого кода и гарантировать, что они не нарушили работу других участков приложения.
• Хорошо написанные тесты — это лучшая документация, которая только может быть у разработчика. Они всегда должны быть актуальными, служат демонстрацией использования API и помогают другим людям понять, как работает кодовая база.
• Руководство компании не заботят ваши тесты: оно заинтересовано в прибыли. В конечном счете польза автоматизированных тестов в том, что они способствуют увеличению прибыли, помогая разработчикам быстрее создавать высококачественное программное обеспечение.
• При написании тестов вы изначально платите высокую цену в виде дополнительного времени на их написание. Но в будущем усилия окупаются. Чем чаще выполняется тест, тем больше времени он вам экономит. Следовательно, чем длиннее жизненный цикл проекта, тем более ценными становятся тесты.