У большинства из нас есть проблема с разъяснением Когда использовать неглубокий, а когда использовать крепление при тестировании с ферментом. В этом уроке я собираюсь обсудить различия между мелководьем и монтировкой, а также их плюсы и минусы.
Перед началом обучения я рекомендую вам иметь проект под названием «testing-demo-app», который я использовал для предыдущих руководств, и ссылка на него ниже.
wasuradananjith / testing-demo-app
Это исходный код для серии руководств« Тестирование с помощью Jest и Enzyme в React … github.com»
мелкий
- Метод shallow используется для визуализации тестируемого нами компонента. Он не отображает дочерние компоненты.
- В версии Enzyme менее 3 неглубокий метод не имеет возможности доступа к методам жизненного цикла. Но в Enzyme версии 3 у нас есть такая возможность.
- Simple shallow вызывает методы constructor, render, componentDidMount (в Enzyme версии 3).
- shallow + setProps вызывает componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate (в Enzyme версии 3) методы.
- shallow + unmount вызывает метод componentWillUnmount.
устанавливать
- Метод mount отображает полную модель DOM, включая дочерние компоненты родительского компонента, в котором мы запускаем тесты.
- Это больше подходит, когда есть компоненты, которые напрямую мешают DOM API или методам жизненного цикла React.
- Но это более затратно по времени выполнения.
- Простое монтирование вызывает методы constructor, render, componentDidMount.
- mount + setProps вызывает componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate.
- mount + unmount вызывает метод componentWillUnmount.
Разница между мелкой и монтировкой на примере
Шаг 1. Создайте новый компонент с именем Form.js.
- Откройте проект под названием «testing-demo-app». Создайте новый компонент с именем Form.js в папке testing-demo-app / src / components со следующим содержанием.
import React, { Component } from 'react'; class Form extends Component { constructor(props) { super(props); this.state = { firstNumber: '', secondNumber: '', componentState:'default' }; this.handleFirstNumber = this.handleFirstNumber.bind(this); this.handleSecondNumber = this.handleSecondNumber.bind(this); } componentDidMount() { this.setState({ componentState: 'mounted' }); } handleFirstNumber(event) { this.setState({ firstNumber: event.target.value }); } handleSecondNumber(event) { this.setState({ secondNumber: event.target.value }); } handleAdd(){ const { firstNumber, secondNumber } = this.state; this.displayResult(parseInt(firstNumber) + parseInt(secondNumber)) } handleSubtract(){ const { firstNumber, secondNumber } = this.state; this.displayResult(parseInt(firstNumber) - parseInt(secondNumber)) } displayResult(result){ alert(result); } render() { const { firstNumber, secondNumber } = this.state; const { operator } = this.props; return ( <form className='form-group'> <fieldset className='form-group'> <label className='form-label'> First Number: </label> <input type="text" id="number1" className='form-input' value={firstNumber} onChange={this.handleFirstNumber}/> </fieldset> <fieldset className='form-group'> <label className='form-label'> Second Number: </label> <input type="text" id="number2" className='form-input' value={secondNumber} onChange={this.handleSecondNumber}/> </fieldset> <div className='form-group'> {operator === '+' && <button id='formButtonAdd' className='btn' type="button" onClick={() => this.handleAdd()}>Add</button> } {operator === '-' && <button id='formButtonSubtract' className='btn' type="button" onClick={() => this.handleSubtract()}>Subtract</button> } </div> </form> ); } } export default Form;
- Перейдите в test-demo-app / src / App.css и очистите содержимое этого файла и добавьте следующие правила css.
html { box-sizing: border-box; font-size: 16px; } *, *:after, *:before { box-sizing: border-box; } body { font: 100% 'Roboto', arial, sans-serif; background: #f5f5f5; } form { padding: 2rem; margin-top: 2rem; margin-right: auto; margin-left: auto; max-width: 23.75rem; background-color: #fff; border-radius: 3px; box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07); } h1 { margin-top: 2%; margin-bottom: 3.236rem; text-align: center; font-size: 1.618rem; } .form-group { padding: 0; border: 0; } .form-group + .form-group { margin-top: 1rem; } label { display: inline-block; margin-bottom: .5rem; font-size: .75rem; text-transform: uppercase; -ms-touch-action: manipulation; touch-action: manipulation; } input, textarea { display: block; padding: .5rem .75rem; width: 100%; font-size: 1rem; line-height: 1.25; color: #55595c; background-color: #fff; background-image: none; background-clip: padding-box; border-top: 0; border-right: 0; border-bottom: 1px solid #eee; border-left: 0; border-radius: 3px; -webkit-transition: all 0.25s cubic-bezier(0.4, 0, 1, 1); transition: all 0.25s cubic-bezier(0.4, 0, 1, 1); } input:focus, textarea:focus { outline: 0; border-bottom-color: #ffab00; } textarea { resize: vertical; } .btn { display: inline-block; padding: .75rem 1rem; width: 100%; margin-top: 1.618rem; font-weight: 400; text-align: center; text-transform: uppercase; color: #fff; vertical-align: middle; white-space: nowrap; background-color: #950aff; border: 1px solid transparent; box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07); cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-transition: all 0.25s cubic-bezier(0.4, 0, 1, 1); transition: all 0.25s cubic-bezier(0.4, 0, 1, 1); } .btn:focus, .btn:hover { background-color: #c78eff; box-shadow: 0 18px 35px rgba(50, 50, 93, 0.1), 0 8px 15px rgba(0, 0, 0, 0.07); } .btn:focus { outline: 0; }
- Импортируйте файл App.css в файл testing-demo-app / src / App.js, добавив следующую строку в файл App.js.
import './App.css';
Шаг 2. Измените компонент Add.js
- Перейдите в test-demo-app / src / components и добавьте следующий контент в файл Add.js.
import React, { Component } from 'react'; import Form from './Form'; class Add extends Component { render() { return ( <div> <h1>Add Function</h1> <Form operator='+'/> </div> ); } } export default Add;
Примечание - ‹h1› и ‹Form› являются дочерними компонентами ‹Add›
Теперь, когда вы запустите сервер, набрав npm start, вы должны получить интерфейс, как показано ниже.
Примечание. Введите 2 числа в поля ПЕРВЫЙ НОМЕР и ВТОРОЙ НОМЕР и нажмите кнопку ДОБАВИТЬ. Должно отображаться предупреждение JavaScript с результатом добавления введенных чисел.
Шаг 3 - Напишите и запустите тест для добавления компонента
- Перейдите в test-demo-app / test и измените Add.test.js следующим содержанием.
import Add from '../src/components/Add'; import Form from '../src/components/Form'; let wrapper; beforeEach(() => { wrapper = shallow(<Add />); }); describe('<Add /> rendering', () => { it('should render one <h1>', () => { expect(wrapper.find('h1')).toHaveLength(1); }); it('should render one <Form>', () => { expect(wrapper.find(Form)).toHaveLength(1); }); it('should render 2 <label>s', () => { expect(wrapper.find('label')).toHaveLength(2); }); });
- Откройте терминал в каталоге проекта и выполните приведенную ниже команду, чтобы запустить тесты в файле Add.test.js.
npm test Add.test.js
- Теперь ваш тест должен завершиться неудачно, как показано ниже.
Почему это не удалось?
- Вы можете видеть, что прошли 2 теста, которые проверяют рендеринг компонентов ‹h1› и ‹Form›.
- Но тест для проверки рендеринга элементов ‹label› не удался.
- ‹h1› и ‹Form› являются дочерними компонентами компонента ‹Add›. (это то, что мы сейчас тестируем)
- Но элементы ‹label› являются дочерними компонентами ‹Form›.
- Метод shallow не отображает элементы ‹label› внутри ‹Form›, поэтому этот тест не проходит.
Решение
- Измените метод shallow в Add.test.js на mount и снова запустите тест.
beforeEach(() => { wrapper = mount(<Add />); });
- Теперь тест должен пройти следующим образом.
- Причина этого в том, что при монтировании отображается полная модель DOM, включая дочерние компоненты в родительском компоненте. Итак, мы полностью отрисовали ‹Form› с ‹label›, которые мы ищем.
Что самое лучшее?
- Рекомендуется как можно чаще использовать поверхностный, поскольку модульные тесты должны быть максимально изолированы.
- Нам не нужно проверять блоки (компоненты) внутри блока (компонента) при запуске одного теста.
- Когда вы используете mount, вы автоматически подвергаетесь логике всех модулей (компонентов) в вашем дереве рендеринга, что делает невозможным тестирование только рассматриваемого компонента.
- При использовании mount это требует больших затрат времени на выполнение, поскольку для этого требуется JSDOM.
оказывать
- Есть еще одна функция, например shallow и mount, которая называется визуализацией.
- Это позволяет отображать статический HTML.
- Оказывает детей.
- Но у него нет доступа к методам жизненного цикла React.
Заключение
Теперь мы знаем плюсы и минусы использования методов shallow и mount, и я надеюсь, что вы сможете четко выбрать, какой из них лучше всего подходит для создаваемого вами теста.
Вы можете найти работу, которую мы проделали в этом руководстве, в ветке под названием tutorial-04 в репозитории git ниже.
wasuradananjith / testing-demo-app
Это исходный код для серии руководств« Тестирование с помощью Jest и Enzyme в React … github.com»
В следующем руководстве я подробнее рассмотрю тестирование с помощью Jest и Enzyme, написав тесты для рендеринга, взаимодействий и вызовов методов жизненного цикла. А пока, до свидания!
Предыдущие уроки
Тестирование с помощью Jest и Enzyme in React - Часть 2 (Как интегрировать Enzyme с Jest в тестировании?)
В предыдущем руководстве мы узнали« Как настроить и запустить протестировать с помощью Jest? . В этом руководстве мы узнаем Как… medium.com
📝 Прочтите этот рассказ позже в Журнале. Просыпайтесь каждое воскресное утро и слышите самые интересные истории, мнения и новости недели, ожидающие в вашем почтовом ящике: Получите примечательный информационный бюллетень›