Главная » Статьи » Тестирование приложений React в 2019 году

Тестирование приложений React в 2019 году

Тестирование приложений React в 2019 году

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

В этом посте мы подробнее рассмотрим некоторые из лучших способов тестирования приложений React. Понятия, которые мы объясним здесь, очевидно, будут применимы к другим средам JavaScript, таким как Vue, или даже к другим языкам, однако, для точности, мы используем для демонстрации React.

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

Предпосылки

В этой статье предполагается следующее:

На вашем компьютере установлен Node.js ≥v6

На вашем компьютере установлен npm

На вашем компьютере установлен React версии 16.8 или выше

На вашем компьютере установлен Create-react-app

У вас есть базовое понимание ReactJS

Общая концепция тестирования

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

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

Фреймворки тестирования JavaScript

На сегодняшний день Jest остается, пожалуй, самой популярной платформой JavaScript с более чем 27 тысячами звезд на Github. Он был разработан Facebook и продолжает поддерживаться командой Jest на Facebook. Jest — это среда тестирования javascript с нулевой конфигурацией, рекомендованная React, она довольно проста в использовании. В 2019 году сообщество JavaScript показало очень впечатляющие показатели принятия — более чем 900 участников.

Другими популярными альтернативами являются Mocha и Jasmine. Mocha претендует на звание наиболее используемой среды тестирования JavaScript. Более 18 тысяч звезд на Github. Это также очень гибкий и открытый для расширений инструмент.

В то же время Jasmine оказался официально рекомендованной средой тестирования Angular.js. У него более 14 тысяч звезд на Github, и это также одна из старейших платформ тестирования с большим количеством ресурсов и поддержкой сообщества. Даже Jest был построен на Jasmine.

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

Настройка Jest

По умолчанию create-react-app поставляется с заданными конфигурациями. Однако для гибкости и полноты мы продемонстрируем, как вручную настроить Jest с webpack для клиентской стороны.

Шаг 1: Запустите npm install —save-dev jest в каталог проекта. Шаг 2: Перейдите к файлу package.json в вашем приложении и добавьте скрипт теста:

"script":{ "test": "jest"
}

Шаг 3: Далее нам нужно настроить файл babelrc.js, потому что у нас есть пресет в package.json с указанием на него. Jest автоматически подхватывает файл и применяет его ко всем тестам.

const isTest = String(process.env.NODE_ENV ) === 'test'
module.export = { presets: [['env', {modules: isTest ? 'commonjs' : false}], 'react'], plugins: [ 'syntax-dynamic-import', 'transform-object-rest-spread',
],
}

Таким образом, babel теперь может определить, что мы проходим тесты, а затем перенесет все модули ES в CommonJS.

Тестирование приложений React

Существует несколько способов тестирования приложений React. Мы рассмотрим некоторые из них.

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

Модульное тестирование включает в себя тестирование отдельных модулей / компонентов программного обеспечения для проверки его правильности. Теперь, как нам добиться этого в приложении React? Если у нас есть компонент авторизации в файле login.js, например, такой:

function Login({ onSubmit }) { return ( <div> <Form onSubmit={e => { e.preventDefault() const { username, password } = e.target.elements onSubmit({ username: username.value, password: password.value, }) }} > <label style={{ justifySelf: 'right' }} htmlFor="username-input"> Username </label> <Input id="username-input" placeholder="Username..." name="username" style={{ flex: 1 }} /> <label style={{ justifySelf: 'right' }} id="password-input"> Password </label> <Input placeholder="Password..." type="password" name="password" aria-labelledby="password-input" /> </Form> </div> )
}

Приведенный выше код представляет собой простой компонент входа в систему, который мы будем выполнять тест в файле login.test.js.

import React from 'react'
import ReactDOM from 'react-dom'
import Login from '../login' test('calls onSubmit with the username and password when submitted',() => { const handleSubmit = jest.fn() const container = document.createElement('div') const form = container.querySelector('form') const {username, password} = form.element username.value = 'Kenny' passwords.value = 'pineapples' form.dispatchEvent(new window.event('submit')) expect{handleSubmit}.toHaveBeenCalledTimes(1) exopect{handleSubmit}.toHaveBeenCalledWith({ username: username.value, password: password.value, }) ReactDOM.render(<Login onSubmit = {handleSubmit} />, container) })

Тест ищет div и передает его в переменную контейнера. Затем из этой переменной контейнера мы создаем форму, вызывая для нее querySelector(‘form’).

Далее мы используем деструктурирование объектов, чтобы получить поля из form.element. Поскольку dispatchEvent() вызывается для события submit, мы можем проверить, что мы делаем с частью формы или какое значение она должна иметь при запуске события submit. Это показывает, что событие должно быть запущено один раз и должно при запуске получать имя пользователя и пароль.

form.dispatchEvent(new window.event('submit')) expect{handleSubmit}.toHaveBeenCalledTimes(1) exopect{handleSubmit}.toHaveBeenCalledWith({ username: username.value, password: password.value, })

И, конечно же, мы можем запустить тест с помощью npm run test.

Тестирование снепшотов

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

render(){ <div> <p> Current count: {this.state.count}</p> <button className = 'increment' onClick ={this.increment}> + </button> <button className = 'decrement' onClick ={this.decrement}> - </button> </div>
}

Представьте, что у компонента был определенный формат, например, кнопка увеличения перед кнопкой уменьшения и тесты проходят, когда это так. Если дизайнер изменяет этот формат, он фактически изменяет формат рендеринга в DOM. Так как же избежать случайных изменений в функции рендеринга DOM?

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

Для выполнения этого теста мы будем использовать форму react-test-renderer, которая даст нам JSON представление теста в определенное время. Затем мы сохраним эти данные с помощью Jest:

import React form 'react'
import Counter from './counter'
import {shallow} from 'enzyme'
import renderer from 'react-test-renderer' describe('Counter component', () => {
it('matches the snapshot', () => { const tree = renderer.create(< Counter/>).toJson()
expect(tree).toMatchSnapshot()
})
it('start with a count of 0', () => { const wrapper =shallow(<Counter/>) const text = wwrapper.find('p').text() expect(tesxt).toEqual('Current count: 0')
})
it('can increment the count when the button is clicked', ()=>{
const wrapper = shallow(<Counter/>)
}

Сначала мы получаем JSON-представление компонента counter, который будет храниться в Jest. Метод expect() принимает дерево в качестве аргумента, и это то, что вызывает сравнение со следующей повторной визуализацией.

Интеграционное тестирование

Как указывалось ранее, интеграционное тестирование — это когда отдельные блоки объединяются и тестируются как группа. Например, если бы у нас было две функции, работающие вместе в одном контексте, мы бы использовали интеграционный тест, чтобы убедиться, что они правильно взаимодействуют друг с другом. Давайте рассмотрим самый простой вариант использования — сложить два числа в компоненте.

export const add = (x,y)=> x + y export const total = (Tax,price) => { return "$" + add(Tax, price)
}

Затем в app.test.js мы делаем:

import {add,total} from './App' test('add', () => { expect(add(1,2)).toBe(3)
}) test('total', () =>{ expect(total(5,20)).toBe(25);
})

Рекомендуемый инструмент тестирования

React-testing-library

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

import React from 'react'
import ReactDOM from 'react-dom'
import {render,simulate} from 'react-testing-library'
import Login from '../login' test('calls onSubmit with the username and password when submitted',() => {
const fakeuser = generate.loginForm
const handleSubmit = jest.fn()
const {container,getByLabelText, getByText} = render(<login onSubmit= {handleSubmit}/>)
const usernameNode = getByLabelText('username')
const passwordNode= getByLabelText('password')
const formNode = container.querySelector('form')
const submitButtonNode = getByText('submit')

В приведенном выше примере мы сосредоточились на тестировании элементов, получая имя, связанное с ними, а не заботясь о пользовательском интерфейсе. Это является основным преимуществом использования этой библиотеки по сравнению с другими альтернативами, такими как enzyme и cypress.

Заключение

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

Автор: Peter Ekene Eze

Источник: https://blog.logrocket.com

Редакция: Команда webformyself.