Вступление
Как и любой разработчик, я предпочитаю инструменты, которые в значительной степени основаны на прошлом опыте. Это означает, что если я не использую этот инструмент и известно, что он помогает разработчикам, то, скорее всего, я не осведомлен по этой теме. Это было особенно верно в отношении Jest, которая стала наиболее широко используемой библиотекой для тестирования приложений ReactJS, поэтому я подумал, что было бы разумно немного изучить эту тему в сообщении в блоге.
В этом посте я хочу поделиться своими отзывами о недавнем использовании Jest, когда я участвовал в проекте next-static после того, как наткнулся на него в репозитории Next.js.
Короче говоря, мне недавно потребовалось перейти от динамического веб-приложения к статическому сайту с помощью проекта next-static. До сих пор это решение работало отлично, поэтому в конечном итоге я внес свой вклад в проект. Первым делом было написать несколько тестов для этого проекта. В течение 2017 года я уделял особое внимание тестированию. Я получил большой опыт написания модульных тестов для приложений ReactJS и был готов к ним приступить.
Шаг первый - создайте нежелательный тест и отправьте его в репозиторий.
Мой первый выбор для написания модульных тестов - это лента. Он очень легкий и предоставляет инструменты, необходимые для написания эффективных модульных тестов. Через несколько минут после настройки среды у меня был готов шаблон для моего первого test.js
файла.
Ниже мы можем увидеть код, отправленный в начальном запросе на вытягивание.
// imports…. // set up for test scope test('<Post />', nest => { nest.test('given no props', assert => { const msg = `should render a post`; const props = makeProps(); const re = RegExp(props); const el = <Post {...props} />; const $ = dom.load(render(el)); const output = $('.post').html(); const actual = re.test(output); const expected = true; assert.same(actual, expected, msg); assert.end(); }); });
После запуска этот журнал для этого теста будет выглядеть, как показано на рисунке ниже.
Разве это не красиво? Я любитель хороших TAP, которые мало что дают на кассете, я знал, что принимаю это как должное, но об этом чуть позже. На этом этапе у меня наконец-то было то, что я мог с уверенностью перенести в следующее статическое репо.
Примерно через день я получил это замечание от владельца проекта.
Но конечно! Зачем я использовал эту технологию каменного века, когда я мог просто подключить Jest! Если отбросить сарказм, меня это не удивило. Я знаю, насколько важным инструментом стал Jest для многих разработчиков, и не собирался с этим бороться. Мне просто не терпелось погрузиться в фреймворк.
Стать единым целым с Jest
Я знал, что перенести этот супербазовый тест не составит труда. Мне просто нужно было знать, как должен быть настроен мой тест, чтобы Jest работал.
В качестве . Одно из основных свойств Jest - это способность волшебным образом запускать тесты, если они:
- в * .test.js или * .spec.js
- они находятся в папке с тестами.
На момент написания моего теста я даже не знал об этих критериях, однако мой код был внутри test.js
файла, так что все работало отлично. Кроме того, я мог полностью исключить этот главный index.test.js
файл, поскольку jest
команда самостоятельно переходила к тестам. Когда jest
запущен, он будет искать в тестах проекта определенные глобальные переменные, которые он предоставляет пользователям. В моем случае мне пришлось заменить test
на describe
функцию Jest w
Глобальные объекты В ваших тестовых файлах Jest помещает каждый из этих методов и объектов в глобальную среду. Для их использования не нужно ничего запрашивать или импортировать.
Эти глобальные переменные позволяют Jest волшебным образом запускать наши тесты без импорта кода. Я не хочу чрезмерно критиковать такой очень известный инструмент, как Jest, однако я очень хорошо осознавал, что за последний год испортил свой глобальный охват. (Да еще по поводу тестирования). Со временем мне стало очень комфортно напрямую импортировать ленту. Потребовалось только написать оператор импорта, и я чувствую себя комфортно, зная, что мой тестовый код полностью самодостаточен и, следовательно, не содержит внешних ошибок. Я не хочу, чтобы это выглядело так, будто я придираюсь к делу. Это всего лишь мой отзыв о библиотеке. При этом я думаю, что эта конфигурация без настройки может позволить начать тестирование как можно скорее.
Когда мой код был изменен в соответствии с критериями Jest, мой модульный тест выглядел следующим образом.
describe('<Post /> with no args', () => { });`
В тесте больше нет обратного вызова assert
, который использовался с лентой. Вместо этого мы видим, что функция Jest expect
используется для создания тестовых утверждений.
expect(actual).toEqual(expected);
В частности, мы видим, что expect
проверяет, чтобы значение внутри actual
было равно expected
, используя toEqual
. (Узнайте больше об ожиданиях Jest-теста здесь.) Благодаря ленте перенос этого теста действительно не занял много времени, и было приятно знать, что я, безусловно, мог бы перенести любой написанный мной тест на использование Jest без каких-либо конфликтов. . Те же концепции, но разные библиотеки. Мне нравится вникать в известные технологии (особенно если я могу понять их с первого взгляда), так что для меня это был беспроигрышный вариант.
У тебя была одна работа
На следующий день после того, как я отправил свой новый тест в PR, мне сообщили, что я не полностью понимаю, о чем меня просят. Я произвел модульный тест, но мне действительно нужно было создать тест-снимок. Большой! Теперь, когда я правильно определил цель, мне просто нужно было выяснить, что именно представляет собой тест снимка.
Войти в тестирование снимков
Как следует из названия, при каждом запуске теста снимок экрана будет выполнять snapshot
компонента. Если есть существующий снимок, Jest сравнит их, чтобы убедиться, что в нашем пользовательском интерфейсе ничего неожиданно не изменилось. Это предназначено для предоставления разработчикам мгновенной обратной связи об их пользовательском интерфейсе. В то время как утверждения модульных тестов предназначены для проверки определенного поведения, тесты моментальных снимков позволяют нам отслеживать тривиальные изменения в нашем пользовательском интерфейсе.
Для этого мы используем метод .toMatchSnapshot()
библиотеки react-test-renderer
. Как только это будет настроено, Jest сравнит снимок нашего компонента с любым предыдущим снимком и проверит, что их содержимое одинаково.
describe('Snapshot::<Post />s', () => { it('should render the contents of the component.', () => { const props = makeProps(); const el = <Component {...props} />; const tree = renderer.create(el).toJSON(); expect(tree).toMatchSnapshot(); }); });
Ниже приведен точный снимок Jest, созданный для компонента <Post/>
. Я не буду объяснять каждую строку, но вы должны легко понять, что должен отображать пользовательский интерфейс.
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Snapshot::<Post />s should render the contents of the component. 1`] = ` <article className="post Post__Article-s1eculme-0 fQItYZ" itemScope={true} itemType="http://schema.org/BlogPosting"; > <header> <a href="/post/test-post" onClick={[Function]} > <h1 className="post--title" itemProp="headline" > Hello </h1> </a> <footer className="post--info" > <span> <time dateTime="7/22/2017" itemProp="datePublished" > about 1 month ago </time> </span> <span itemProp="author" > User </span> </footer> </header> <div className="post--body" dangerouslySetInnerHTML={ Object { "__html": "<p>lorem ipsum is the name making tests is this game</p> ", } } /> <footer> <small className="post--tags" > <span> Filed under: </span> <span className="post--tag" itemProp="keywords" > <a href="/tag/javascript" onClick={[Function]} > javascript </a> , </span> <span className="post--tag" itemProp="keywords" > <a href="/tag/angular" onClick={[Function]} > angular </a> </span> </small> </footer> </article> `;
Как видите, Jest создал удобочитаемое представление нашего пользовательского интерфейса. С этого момента все будущие реализации <Post/>
будут проверяться на основе этого снимка. Чтобы лучше понять, что это означает, давайте посмотрим, что произойдет, когда мы удалим <footer>
из нашего Post
компонента и запустим наш тест снимка.
Взглянув на это изображение, мы видим, что Jest ожидает <footer>
div и не может найти его внутри нашего компонента. В результате мы видим знак-
, означающий, что блок кода был удален из файла. Если бы меня попросили удалить этот нижний колонтитул, я бы подтвердил это изменение и запустил jest -u
, чтобы обновить свой снимок, но я этого не сделал. Вместо этого я создавал начальный снимок для этого компонента, и поэтому мне не нужно было беспокоиться о предыдущих снимках. Тот факт, что я создал отправную точку для тестов фьючерсов, был достаточно хорош.
На этом этапе я еще больше видел преимущества, которые Jest привносит в проект, но я еще не был полностью уверен в том, что он является конечной частью фреймворков для тестирования. Он предназначен для очень быстрой работы, но я обнаружил, что мои тесты на самом деле выполнялись немного быстрее с лентой, что имеет смысл из-за ее легкости.
Кроме того, лента позволяет мне использовать TAP. Называйте меня старомодным, но TAP существует с 1980-х годов. Он старше меня, и технологии, просуществовавшие так долго, обычно не зря высекаются в камне. Я лично не пробовал интегрировать пользовательский репортер TAP с Jest, но, как я понял, это довольно сложная задача. Это конец света? Нет. Вовсе нет, но стоит отметить. С другой стороны, когда используется флаг —watch
, Jest предлагает довольно крутой интерфейс, который упрощает выполнение определенных тестов. —watch
сохраняет работу Jest после создания тестов моментальных снимков и предлагает нам возможность обновлять наши предыдущие снимки, просто нажав u
.
Заключительные слова
Нельзя отрицать, что Jest упрощает начало тестирования кода. На самом деле, легко - это легкомысленно. Как я только что упомянул, это было настолько просто, что я сначала был немного смущен тем, как это должно было работать, но дело в том, что это действительно сработало. Помимо безразличия к использованию глобальных переменных и невозможности легко распечатать результаты тестов в TAP, я не сомневаюсь в эффективности Jest. Напротив, я очень рад видеть, что еще может предложить Jest, поскольку я знаю, что это не последнее, что я увижу!