Тестирование является очень спорным понятием в разработке программного обеспечения. Несмотря на то, что всем сложно договориться о лучших способах тестирования или о лучших инструментах, или даже об уровне приоритета тестирования, мы все же можем согласиться с тем, что это очень важный аспект любого продукта и тестирование следует рассматривать серьезно.
В этой статье мы подробнее рассмотрим некоторые из лучших способов тестирования приложений 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. На Github более 18 тысяч звезд. Помимо массивной экосистемы, у Mocha есть устоявшиеся варианты с отличной документацией. Она также очень гибкая и открыта для многих расширений.
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 теперь может распознать, что мы проходим тесты, а затем переносим все наши ESmodules в 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 и покажет, как это сделать.
Источник - logrocket.com