Руководство по модульному тестированию на React

Сегодня тестирование стало важной частью процесса разработки приложений. Он должен проходить все проверки и подтверждения на каждом этапе. Давайте посмотрим, как выполняется модульное тестирование приложений React.

Что такое модульное тестирование?

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

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

Давайте посмотрим на инструменты, широко используемые для тестирования приложений React:

Шутка

Jest - это средство запуска тестов, которое будет запускать все ваши тестовые наборы и тестовые случаи. Jest вводится в основном для тестирования javascript и приложений для реагирования. Нам нужно вызвать шутку из командной строки, чтобы запустить наши тестовые примеры. У нас также могут быть дополнительные конфигурации для индивидуальной настройки.

Установка

npm install --save-dev jest

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

--config <path/to/file.js/mjs/cjs/json>

Для получения дополнительной информации о jest обратитесь к официальной документации здесь https://jestjs.io/docs/en/getting-started.

Давайте создадим файл jest.config.json в нашей корневой папке и добавим этот сценарий в ваш файл package.json для запуска тестов:

{
 ...
  "scripts": {
   "test": "jest",
   }
  ...
}

И вы настроили шутливую среду для своего приложения React!

Фермент

Фермент - это библиотека, которая используется во многих полных библиотеках тестирования вместе с jest. Он специально используется для рендеринга компонентов и обхода DOM.

Если вы создаете приложение React, то лучшим сочетанием для тестирования приложений React будет jest и энзим. Помните, что jest - это средство запуска тестов для запуска наших тестовых примеров с утверждениями, тогда как фермент - это библиотека, используемая вместе с jest, которая предоставляет различные методы рендеринга, такие как (неглубокий, монтирование и т. Д.) Для нашего компонента React, а DOM пересекает визуализированный выход.

Давайте посмотрим на настройку фермента:

Установка

npm install --save-dev enzyme

Ферменты предоставляют адаптеры для работы с различными версиями React. Итак, давайте установим адаптер в зависимости от нашей версии React. Здесь мы устанавливаем React16.

npm install --save-dev enzyme-adapter-react-16

Теперь нам нужно настроить наш фермент с помощью адаптера, который мы установили в нашей тестовой среде. Итак, давайте создадим jest.setup.js и добавим в файл следующий код:

import React from 'react';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });

Теперь добавьте этот путь к установочному файлу в наш файл jest.config.json:

{
 "setupFilesAfterEnv": [
   "<rootDir>/jest.setup.js"
 ]
}

Вот и все! Вы создали фермент в своей шутливой среде.

Очень важно решить, что нужно тестировать, а что не нужно тестировать.

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

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

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

Рассмотрим небольшой пример, чтобы понять:

1.

import React from 'react';
const DisplayName = ({name}) => {
 return (
   <div>
     Welcome {name}!
   </div>
 );
};
export default DisplayName;

2.

import React, { useState } from 'react';
import DisplayName from './displayName';
export const validateName = (name) => {
 if((name && isNaN(name)) || !name)
   return false
 return true
}
const User = () => {
 const [name,setName] = useState(null);
 const [error,setError] = useState(false);
  const setUserName = (event) =>{
   const {value} = event.target;
   var isOk = validateName(value);
   setError(isOk);
   setName(value);
 }
 return (
   <div>
     <DisplayName name={name} />
     <input type="text" value={name} onChange={setUserName}/>
     {error && <div>Error</div>}
   </div>
 );
};
export default User;
  • Компонент DisplayName, который получает свойство имени в качестве реквизита и отображает его.
  • Компонент User, имеющий текстовый ввод в качестве свойства name, проверяет имя пользователя на его тип и устанавливает ошибку, если обнаруживает ее.

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

Модульное тестирование приведенного выше примера

Есть два основных подхода к тестированию наших компонентов React:

  1. Тестирование снимков
  2. Логическое / функциональное тестирование

1. Тестирование снимков

Snapshot Test создает снимок вашего компонента в текущем состоянии, когда вы запускаете тест, и сохраняет его в папке с именем «__snapshots__».

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

Как проводится тестирование снимков?

Во-первых, нам нужно установить утилиту react-test-renderer для рендеринга компонента в нашем тесте.

npm install --save-dev react-test-renderer

Давайте реализуем наш первый тест снимка, записав приведенный ниже тестовый пример в файл UserName.spec.js:

import React from 'react';
import renderer from 'react-test-renderer';
import DisplayName from './displayName';
describe('DisplayName', () => {
 test('should render Vrushali', () => {
   const component = renderer.create(<DisplayName name={"Vrushali"} />);
   let tree = component.toJSON();
   expect(tree).toMatchSnapshot();
 });
});

Сначала мы отрендерили компонент DisplayName, преобразовали его в JSON и проверили, совпадает ли он с предыдущим сделанным снимком. Давайте запустим тест командой «npm run test» на cmd и посмотрим.

Если вы запустите тест в первый раз, он сгенерирует снимок выходных данных компонентов и сохранит его в папке «__snapshots__». Вы можете посмотреть, какую структуру он хранит.

Теперь давайте изменим наш компонент DisplayName и снова запустим тест:

import React from 'react';
const DisplayName = ({name}) => {
 return (
   <div>
     <p>Welcome {name}!</p>
   </div>
 );
};
export default DisplayName;

Вы можете видеть, что это показывает изменение в нашем компоненте, и тест не проходит, поскольку он не соответствует нашему предыдущему снимку. Это указывает на то, что либо обнаружена ошибка в компоненте, который необходимо исправить, либо есть изменение реализации, и вам просто нужно обновить снимки. Вы можете обновить снимки с помощью опции «-u». Точно так же мы также можем добавить тест снимка для нашего родительского компонента.

2. Логическое / функциональное тестирование

Для тестирования функциональности проверки давайте добавим еще несколько тестов в наш код.

import React from 'react';
import renderer from 'react-test-renderer';
import DisplayName from './displayName';
import { validateName }  from './index';
describe('DisplayName', () => {
 test('should render Vrushali', () => {
   const component = renderer.create(<DisplayName name={"Vrushali"} />);
   let tree = component.toJSON();
   expect(tree).toMatchSnapshot();
 });
});
describe('Validation',()=>{
 test('should set the error if input is number',()=>{
   const name = 123;
   const error = validateName(name);
   expect(error).toBeTruthy();
 });
 test('should reset the error if input is empty',()=>{
   const name = null;
   const error = validateName(name);
   expect(error).toEqual(false);
 });
})

Здесь мы добавили два тестовых примера:

  1. Проверяет, было ли установлено сообщение об ошибке, если пользователь вводит числовой ввод для своего имени.
  2. Проверяет, сбрасывает ли сообщение об ошибке значение false, если поле ввода пусто для свойства name.

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

Теперь, если мы запустим тесты, мы должны увидеть следующий результат.

Если проверка неверна, запущенные тесты сообщат вам об этом, иначе все тесты пройдут. Разделение логики очень помогает в сложном коде, чтобы его можно было протестировать во всех возможных случаях, а также выглядит более понятным способом понимания кода.

Что мы узнали?

  • Для реализации тестирования код должен быть менее зависимым, что приведет к более модульному и многократно используемому коду.
  • Наличие хороших тестов помогает проверять изменения с помощью неудачных тестовых примеров при каждом запуске
  • Более быстрое развитие - КАК?
  • Прежде чем перейти к коду, мы сначала пишем тесты, учитывая все возможности, что код может дать сбой. Это помогает нам писать более эффективный и безошибочный код.
  • Без тестов мы проводим тестирование для разработчиков, имея при этом консоли, точки останова, отладчики и графический интерфейс, чтобы увидеть, где происходит сбой кода.
  • Модульные тесты менее затратны, чем тесты для разработчиков.
  • Перед тем, как начать разработку, мы проясним наши требования к коду с помощью тестов, которые увеличивают нашу скорость при написании логики, вместо того, чтобы находить ошибки одну за другой и затем исправлять их.