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

Что, если бы я сказал вам, что модульное тестирование на самом деле решает многие проблемы, с которыми вам еще предстоит столкнуться? Что, если бы я сказал вам, что предварительная загрузка дополнительного времени на разработку через тестирование и разработку на основе поведения может фактически сократить общее количество времени, необходимое для написания вашего приложения? Я уже заинтересовал вас?

Во-первых, что такое разработка на основе тестов и действий?

Эти два подхода к развитию часто работают в тандеме друг с другом. Лучшее TDD сообщает BDD, и наоборот. Оба задают вопрос: какова ваша цель для конкретной части вашего приложения?

Разработка через тестирование (TDD) носит чисто технический характер и работает по очень шаблонной процедуре. Обсудите тест, напишите тест, не пройдете тест, пройдете тест и, если необходим рефакторинг теста. Смыть, прополоскать, повторить. Два элемента, о которых в первую очередь заботится TDD, - это input теста и output теста. Давайте посмотрим на очень простой пример этого с использованием Mocha Chai для тестирования наших моделей баз данных:

  1. Обсуждение - Нам нужна модель Продукта, у которой есть название. Тип имени должен быть строкой, и имя должно быть уникальным.
  2. Запись - Mocha Chai имеет трехуровневую структуру, которая очень проста в использовании. Напишите блок describe, который передает в параметр описание вашего теста, блок it, который передает описание конкретной части, которую вы изолируете для тестирования, и expect, который передает входные данные и ожидает выходных данных. Этот третий уровень называется утверждением, и mocha предлагает 3 библиотеки утверждений между ожидать, должен и утверждать. В моих чисто предпочтительных целях мы будем использовать ожидать. Когда блоки будут написаны, это будет выглядеть так:

3. Ошибка - пока не беспокойтесь о ловушке beforeEach в блоке describe. Мы вернемся к этому позже, когда будем говорить об организации скриптов. Итак, тесты пока не проходят, потому что наша Product модель еще не определена. Вот что мне говорит моя подсказка:

4. Пройдено - Мы хотим видеть две вещи из нашей Product модели - что это строка типа и что она уникальна. Давайте определим модель Product с полем имени, имеющим тип string. Теперь мы видим, что один тест проходит:

5. Рефакторинг. Хотя наша модель соответствует критериям первого теста, она также должна пройти второй. Давайте добавим валидатор для отклоняемого экземпляра, если он не уникален, и протестируем его снова.

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

Разработка, основанная на поведении (BDD), пытается решить то, что кажется. Он представляет код в среде реального времени с переменными реального времени. Какой результат мы хотели бы видеть в различных условиях? BDD, в отличие от TDD, не ставит своей целью ответить на технические вопросы о том, как вывод должен быть произведен с помощью написанного кода, и не предполагает линейного потока TDD - если переменная идет таким образом, она естественным образом выходит сюда. Фактически, BDD не требует письменного кода. BDD просто хочет знать, можем ли мы произвести желаемый результат в любом из возможных условий, с которыми эта функция может столкнуться в приложении. Следовательно, как он себя ведет.

Таким образом, жизненный цикл модульного тестирования может выглядеть следующим образом:

  • Первый этап TDD для определения базовой модели и RESTful API
  • Первый раунд BDD, чтобы узнать, с какими условиями могут столкнуться наши данные в реальном времени.
  • Выполните рефакторинг кода, чтобы сделать код динамическим, чтобы мы могли постоянно видеть желаемый результат при любых условиях, обсуждаемых в BDD.

Что такое гибкая разработка?

Кратко говоря, гибкая разработка - это философия разработки, которая работает с кросс-функциональной, самоорганизующейся командой, которая стремится обеспечить непрерывную поставку продукта владельцем продукта - в нашем случае программного обеспечения или приложения, которое мы пишем. Часто это делается с помощью методологии, обычно называемой Scrum Framework. Структура Scrum - это, по сути, план передовых практик, который включает отставание, спринт, ежедневный спринт (проверки) и ретроспективу (или обзор). Более подробный обзор Agile можно прочитать в Agile Manifesto.

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

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

Давайте вернемся к нашему предыдущему примеру с моделью Product. Мы создаем приложение для электронной коммерции, в котором у каждого продукта будет много Review. Мы не уверены, как команда Front-end хочет обрабатывать загрузку отзывов. Мы знаем, что каждый раз, когда запрашивается один продукт, ему потребуется доступ к его обзорам, но также есть много способов сделать это. Мы спрашиваем нашу команду Front-end и выясняем, что они не хотят делать слишком много ненужных вызовов на сервер, поэтому мы решаем, что было бы лучше загружать все продукты, которые потребуются от первоначального вызова, чтобы получить все продукты. . В итоге мы определяем нашу модель следующим образом:

Это кажется очень мелкой деталью. Я имею в виду, что мы почти не добавили строчки кода. Но если мы решили, как мы хотим, чтобы конкретный фрагмент кода выполнял свой вывод на протяжении всего жизненного цикла в приложении с TDD и BDD при создании серверной части нашего приложения, мы уже самоорганизуются, самонастраиваются, и кросс-функциональность, потому что мы никогда не изолируем только технические детали нашей конкретной задачи. Мы строим бэкэнд с полным мышлением.

В этом конкретном сценарии, если бы мы не предприняли тех шагов, которые мы сделали, нам все равно придется загружать наши обзоры нашими продуктами. Но это будет просто в гораздо менее контролируемой среде. Об этом нам сообщит ошибка. Мы предпримем самые немедленные шаги, чтобы решить нашу проблему, но, скорее всего, пропустим вопрос о том, уделяем ли мы меньше или больше приоритетов нашему серверу. Это может привести к большему количеству вызовов AJAX и более медленной программе в целом в зависимости от размера приложения.

Когда мы начинаем наши приложения с использованием BDD и TDD, это закладывает основу для естественного функционирования с гибким мышлением.

Теперь примечание об организации скриптов

Модульное тестирование может стать беспорядочным, если мы начнем тестировать слишком много моделей и слишком много файлов маршрутов. Помните тот beforeEach крючок, к которому я сказал, что мы вернемся? Что ж, сейчас самое время. Когда мы тестируем с помощью Mocha Chai - и другого фреймворка, на который у нас не было времени, Supertest - мы пытаемся имитировать или моделировать реальную среду, чтобы мы могли изолировать наши функции для тестирования. На веб-сайте электронной коммерции мы можем увидеть модели Product Review LineItem и User. Точно так же у нас, скорее всего, будет 4 файла для API для каждой модели. В ходе тестирования будет определено множество экземпляров, и мы не хотим отслеживать, что уже есть в нашей базе данных, а что нет, потому что наша цель имитации среды на самом деле состоит в том, чтобы четко изолировать то, что мы тестируем.

Я прошу перед каждым следующим it блоком, я хочу, чтобы блок describe возвращал мне только что синхронизированную модель Продукта. Включение {force:true} просто просит стереть все, что уже есть в базе данных в этой модели. Другой способ уничтожить базу данных - вместо включения {force:true} мы можем включить блок afterEach после beforeEach, который запрашивает усечение модели продукта:

Если бы у нас был один файл-бегемот для тестирования каждой модели и каждого маршрута, мы могли бы спокойно написать один скрипт для тестирования в нашем package.json. Но тогда мы бы не следовали принципу модульности, который приводит к невероятно дезорганизованному коду. В противном случае у нас будет несколько файлов тестирования, каждый из которых имеет свои отдельные beforeEach и afterEach хуки. Как мы должны протестировать эти файлы в нашем скрипте?

Если вы написали сценарий, который тестировал более одного файла за раз, который будет повторно синхронизировать одни и те же модели и / или базу данных, ваша оболочка bash, скорее всего, будет кричать на вас с таким сообщением:

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

Если вы полностью посмотрите на последний скрипт "test": "mocha -w db/testing/*, мы просим запустить тест на фреймворке мокко для всех файлов в db/testing пути к файлу, и чтобы он постоянно отслеживался на предмет сохраненных изменений. Принимая во внимание несколько наших тестовых файлов, этот скрипт попытается запустить 4 файла модели одновременно, и это будет катастрофой ограничения.

Модульное построение ваших сценариев тестирования, как показано выше, и тестирование каждой модели и каждого файла API в собственном сценарии часто гарантирует отсутствие ошибок ограничений, если только они не происходят в it блоках определенного файла. В базу данных будет отправляться только один запрос на синхронизацию.

Модульность также может быть достигнута путем включения всех тестов модели в один db.spec.js файл и всех тестов API в один api.spec.js файл, каждый со своими индивидуальными сценариями. Или, если вы действительно начинаете фантазировать и хотите использовать Enzyme для внешнего тестирования, вы можете добавить test:Client, который специально просматривает ваш файл тестирования на стороне клиента.

Заключение

Среда гибкой разработки не может быть гарантирована письменной формулой практик. У каждой команды будет свой собственный ритм работы между участниками команды и способы создания собственного рабочего процесса Scrum. Но если мы хотим работать с ДНК Agile, заложенной в зародыше нашего проекта, TDD и BDD станут отличной стартовой площадкой.