Мой путь к программированию начался в 2020 году, когда началась пандемия, и моим первым языком сценариев был JavaScript. Я предполагал, что базовые концепции JS будут легкими, учитывая, что я занимаюсь этим уже 2 года. Я ошибался.

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

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

TDD помогает вам писать более качественный код, но это сложнее, чем просто написать код. Вы должны выбрать правильный ресурс(ы) для тестирования, и вы должны изучить новый синтаксис и как применить тест к вашему коду. Очень сложно, особенно для нового разработчика, который все еще изучает основы программирования.

Но мне уже 2 года, и мои базовые навыки программирования сильны. Так что планирование дальнейшего развития моих навыков TDD должно быть довольно простым для меня, верно?

Мы планируем, Бог смеется!

Я использую TDD для создания приложения React, поэтому я использую библиотеку Jest. Первоначально я выбрал тестовую утилиту (Enzyme), чтобы помочь в тестировании выходных данных моих компонентов, и я боролся с ней пару дней, прежде чем в конечном итоге отказался от нее из-за проблем с адаптером.

Затем я выбрал Jest и библиотеку тестирования React, поскольку эта зависимость включается при использовании среды Create React App для создания приложения React.

Я решил создать приложение React, которое изучающий английский язык может использовать для создания тем (например, визит к врачу), а затем добавлять слова, относящиеся к этой теме, содержащие определения и предложения, необходимые для эффективного общения в этой английской среде. Они могут использовать приложение, чтобы освежить свои знания английского языка и попрактиковаться в общении на разные темы на английском языке.

Для начала я использовал команду create-react-app в терминале, чтобы создать новое приложение.

Я создал файл SubjectsList.js для хранения функционального компонента предметов и файл SubjectsList.test.js для хранения тестов для этого компонента.

Затем я подумал о функциональности приложения, которую хотел закодировать. Я решил, что если пользователь не создал ни одной темы, приложение должно показывать сообщение «Нет тем». После создания темы сообщение должно исчезнуть.

Поскольку я практиковал TDD, я начал с написания теста первым в тестовом файле. Мне нужно было визуализировать конкретный компонент, вывод которого я хотел протестировать. Поэтому я импортировал методы рендеринга и экрана из библиотеки тестирования реакции и импортировал свой компонент SubjectsList, чтобы иметь к нему доступ.

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

Теперь, когда SubjectsList был виртуально отрендерен, мне нужно было захватить элемент, содержащий сообщение «Нет тем». Сообщение должно существовать в виртуально отображаемом SubjectsList, потому что ни одна тема не была создана. Я использовал getByText для сохранения копии элемента, содержащего сообщение, в переменной noSubjectsMessage.

Затем я использовал ожидание, чтобы написать утверждение, что переменная noSubjectsMessage, содержащая сообщение, должна быть в отображаемом документе. Мой завершенный тест выглядел так:

Теперь, чтобы запустить тест. Я открыл терминал и перешел в каталог своего приложения, а затем запустил команду npm test. [ПРИМЕЧАНИЕ Тест будет продолжать выполняться и обновляться при каждом изменении и сохранении; чтобы остановить тест, используйте команду control + c. ]

Неудачный тест был обнаружен, как и ожидалось. Он показал, что один тестовый набор (мой тестовый файл) не удался. Это также показало, что я написал один тест в этом файле, который не прошел, поэтому весь пакет не прошел.

Я прокрутил, чтобы увидеть больше информации о сбое теста, и нашел тест по его подробностям, показанным красным. Выяснилось, что тест провалился из-за TestingLibraryElementError, потому что не удалось найти элемент с текстовым сообщением «Нет субъектов».

Я еще не написал код в своем файле компонента, чтобы показать это сообщение, поэтому тест должен был провалиться. Все идет нормально.

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

Я импортировал useState для настройки состояния субъектов внутри компонента. Поскольку пользователь мог создать более одного субъекта, мне понадобился массив. А так как субъектов еще не было, массив начинался бы пустым.

Должен признаться, я испытал облегчение от того, что трудная часть позади, и все, что мне нужно было сделать, это закодировать мой простой тернарный оператор внутри return, чтобы пройти тест. Мое возвращение к основам произошло при попытке закодировать этот базовый тернарный оператор. Я использовал приведенный ниже код, и мой тест НЕ прошел!

Это привело к тому же сообщению об ошибке, что и раньше. Логика оказалась здравой;

  • проверьте переменную subject для предметов
  • если у него были темы, не создавайте сообщение
  • если у него нет тем, создайте сообщение без тем

В переменной subject явно НЕ было субъектов из-за пустого массива. Эта переменная субъекта использовалась для определения истинности или ложности моего троичного утверждения, и она была пустой, НЕТ СУБЪЕКТОВ! Так почему же тест все еще не прошел?

Мне потребовалось довольно много времени, прежде чем я понял, что это не работает, потому что массив оценивается как правдивый, даже если он пуст! Итак, моя переменная subject в основном регистрировала: «Да, предметы существуют, хотя массив пуст и в нем нет предметов». И из-за этого сообщение «Нет тем» не создавалось. Поскольку тест ожидал, что это сообщение будет существовать в виртуально визуализируемом компоненте, он завершился неудачей, поскольку сообщение так и не было создано.

Мне потребовалось много времени, чтобы понять это, потому что я был уверен, что знаю основы JavaScript относительно того, что было правдой, а что ложью. Мне никогда не приходило в голову, что проблема была в пустом массиве. Я задавался вопросом, не работает ли компьютер, прежде чем я подумал, что это может быть пустой массив. Вот насколько я был уверен в своих основах JavaScript.

В конце концов я просмотрел код, проверяя каждую часть, независимо от того, считал ли я ее правильной. Наконец, я был предупрежден о том, что происходит, когда я использовал оператор взрыва (!) для проверки истинности или ложности статуса значения субъекта. Двойной взрыв (!!) показывает логический статус значения (истина или ложь). Поэтому я ожидал, что !!subjects (то же самое, что !![]) будет ложным. Это не так. Это было правдой.

Представьте мой шок, через 2 года после совершения этой ошибки!

Этот путь TDD очень сложен, но он повышает уровень моих навыков программирования, возвращая меня к основам. Мне, как разработчику, это именно то, что нужно.

P.S. Если вам интересно, как я решил проблему…

ОРИГИНАЛ: я сослался на ложную пустую строку (« ») вместо настоящего пустого массива. Пустая строка определенно является ложной (я проверил, хотя знал это как факт). Поэтому я изменил начальное состояние субъекта на массив, содержащий пустую строку. Затем я использовал нотацию индекса [0] для ссылки на эту пустую строку (« ») вместо пустого массива в троичном выражении. Код ниже, наконец, прошел тест.

ИЗМЕНЕНО: обдумывая свое первоначальное решение, я понял, что запуск объектов с пустой строкой, содержащейся в массиве, может привести к ошибкам подсчета объектов или проблемам с рендерингом при добавлении или удалении объектов. Постоянно пустая строка, содержащаяся в массиве, может вызвать эти проблемы. В идеале массив должен начать содержать ничего, даже пустую строку. Но мне нужно, чтобы переменная subject была ложной, а пустой массив — правдивым.

Поэтому я удалил пустую строку из массива в useState, но оставил все как есть, и тест пройден!

Однако, после дальнейшего рассмотрения, несмотря на то, что тест пройден, использование нулевой нотации индекса на самом деле не отражало того, что должен делать мой код. Явная проверка индекса 0 означает, что мне нужен именно этот индекс, а мне нет. Я хочу убедиться, что весь массив полностью пуст. Лучшее представление для этого — использование subject.length. Использование subject.length удовлетворяет требованию ложности, потому что оно оценивается как ноль, когда субъекты пусты, а ноль является ложным, и это ясно указывает, что я проверяю, есть ли вообще какие-либо субъекты в массиве. Поэтому я провел рефакторинг subject в своем троичном операторе и заменил subject[0] на subject.length.

И мой тест все же прошел!

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