Обратите внимание, что с React тестируемые компоненты поставляются бесплатно, прямо из коробки. Здесь нет ничего особенного — обработчик событий, JSX и метод рендеринга.
Следующим компонентом React в иерархии является GreatApeList
class GreatApeList extends Component {
render() {
let rows = [];
this.props.apes.forEach((ape) => {
if (!this.props.showExtantOnly) {
rows.push(<GreatApeRow key={ape.name} ape={ape} />);
return;
}
if (ape.isExtant) {
rows.push(<GreatApeRow key={ape.name} ape={ape} />);
}
});
return (
<div>
{rows}
</div>
);
}
}
Это компонент React, который имеет компонент GreatApeRow
Это самая мощная композиционная модель React на работе. Обратите внимание на отсутствие наследования при создании повторно используемых, но тестируемых компонентов.
В программировании композиция объектов — это шаблон проектирования, который включает элементы, управляемые данными. Чтобы думать об этом иначе, GreatApeList
GreatApeRow
Именно эти отношения между компонентами пользовательского интерфейса определяют дизайн. В компоненты React встроен этот образ мышления. Такой взгляд на элементы пользовательского интерфейса позволяет вам написать несколько хороших модульных тестов.
Здесь вы проверяете флаг this.props.showExtantOnly
Это свойство showExtantOnly
GreatApeSearchBar
Для модульных тестов, как вы проводите модульное тестирование компонентов React, которые зависят от других компонентов? Как насчет компонентов, переплетенных друг с другом? Это отличные вопросы, о которых нужно помнить, поскольку мы скоро приступим к тестированию. У компонентов реагирования могут быть секреты, которые можно открыть.
А пока давайте посмотрим на GreatApeRow
class GreatApeRow extends Component {
render() {
return (
<div>
<img
className="GreatApeRow-image"
src={this.props.ape.image}
alt={this.props.ape.name}
/>
<p className="GreatApeRow-detail">
<b>Species:</b> {this.props.ape.name}
</p>
<p className="GreatApeRow-detail">
<b>Age:</b> {this.props.ape.age}
</p>
</div>
);
}
}
С компонентами React практично изолировать каждый элемент пользовательского интерфейса с помощью лазерной фокусировки на одной проблеме. Это имеет ключевые преимущества, когда речь идет о модульном тестировании. Пока вы придерживаетесь этого шаблона проектирования, вы сможете легко писать модульные тесты.
Тестовые утилиты
Давайте вспомним нашу самую большую проблему, когда речь заходит о тестировании компонентов React. Как выполнить модульное тестирование отдельного компонента в отдельности? Ну, как оказалось, есть изящная утилита, которая позволяет вам это сделать.
Shallow Renderer в React позволяет визуализировать компонент на один уровень глубиной. Отсюда вы можете утверждать факты о том, что делает метод рендеринга. Что примечательно, так это то, что для этого не требуется DOM.
Используя ES6, вы используете его так:
import ShallowRenderer from 'react-test-renderer/shallow';
Чтобы модульные тесты выполнялись быстро, вам нужен способ тестирования компонентов изолированно. Таким образом, вы можете сосредоточиться на одной проблеме, протестировать ее и перейти к следующей проблеме. Это расширяет возможности по мере роста решения и возможности рефакторинга по желанию — оставаясь близко к коду, быстро внося изменения и получая уверенность, что оно будет работать в браузере.
Одним из преимуществ этого подхода является то, что вы лучше думаете о коде. Это дает лучшее решение, которое имеет дело с проблемой под рукой. Я нахожу это свободным, когда ты не прикован к куче отвлекающих факторов. Человеческий мозг делает ужасную работу, имея дело с более чем одной проблемой одновременно.
Остается только один вопрос: как далеко эта маленькая утилита может увести нас с компонентами React?
Положил все это вместе
Взгляните, например, на GreatApeList
Какую главную проблему вы пытаетесь решить? Этот компонент показывает вам список отличных обезьян на основе фильтра.
Эффективным модульным тестом является передача списка и проверка фактов о том, что делает этот компонент React. Мы хотим, чтобы он фильтровал великих обезьян на основе флага.
Один из подходов состоит в том, чтобы сделать это:
import GreatApeList from './GreatApeList';
const APES = [{ name: 'Australopithecus afarensis', isExtant: false },
{ name: 'Orangutan', isExtant: true }];
const renderer = new ShallowRenderer();
renderer.render(<GreatApeList
apes={APES}
showExtantOnly={true} />);
const component = renderer.getRenderOutput();
const rows = component.props.children;
expect(rows.length).toBe(1);
Обратите внимание, что я тестирую компоненты React с использованием Jest. Подробнее об этом см. « Как тестировать компоненты React с помощью Jest ».
В JSX взгляните на showExtantOnly={true}
Синтаксис JSX позволяет вам установить состояние ваших компонентов React. Это открывает множество способов для модульного тестирования компонентов в определенном состоянии. JSX понимает основные типы JavaScript, поэтому true
Со списком в стороне, как насчет GreatApeSearchBar
Он имеет этот обработчик события в свойстве onChange
Один хороший юнит-тест должен сделать это:
import GreatApeSearchBar from './GreatApeSearchBar';
let showExtantOnly = false;
const onChange = (e) => { showExtantOnly = e };
const renderer = new ShallowRenderer();
renderer.render(<GreatApeSearchBar
showExtantOnly={true}
onShowExtantOnlyInput={onChange} />);
const component = renderer.getRenderOutput();
const checkbox = component.props.children[0];
checkbox.props.onChange({ target: { checked: true } });
expect(showExtantOnly).toBe(true);
Для обработки и тестирования событий вы используете один и тот же метод визуализации. Метод getRenderOutput
Здесь onShowExtantOnlyInput
onChange
На более тривиальном модульном тесте, как насчет компонента GreatApeRow
Он отображает отличную информацию об обезьяне с использованием HTML-тегов. Оказывается, вы можете использовать мелкий рендер для проверки этого компонента.
Например, давайте удостоверимся, что мы визуализируем изображение:
import GreatApeRow from './GreatApeRow';
const APE = {
image: 'https://en.wikipedia.org/wiki/File:Australopithecus_afarensis.JPG',
name: 'Australopithecus afarensis'
};
const renderer = new ShallowRenderer();
renderer.render(<GreatApeRow ape={APE} />);
const component = renderer.getRenderOutput();
const apeImage = component.props.children[0];
expect(apeImage).toBeDefined();
expect(apeImage.props.src).toBe(APE.image);
expect(apeImage.props.alt).toBe(APE.name);
С компонентами React все это сосредоточено вокруг метода render
Это делает несколько интуитивно понятным, чтобы точно знать, что вам нужно проверить. Благодаря мелкому рендереру вы можете лазерно сфокусироваться на одном компоненте, исключая при этом шум.
Вывод
Как показано, компоненты React очень тестируемы. Нет оправдания отказываться от написания хороших модульных тестов для ваших компонентов.
Приятно то, что JSX работает для вас в каждом отдельном тесте, а не против вас. С JSX вы можете передавать логические значения, обратные вызовы или все, что вам нужно. Имейте это в виду, когда вы решите самостоятельно протестировать компоненты React.
Утилита тестирования мелкого рендерера дает вам все необходимое для хороших модульных тестов. Он отображает только один уровень и позволяет вам тестировать в отдельности. Вас не интересует какой-либо произвольный дочерний элемент в иерархии, который может нарушить ваши юнит-тесты.
Мне нравится инструмент Jest, который дает вам обратную связь только по конкретным файлам, которые вы меняете. Это сокращает петлю обратной связи и добавляет фокусировку лазера. Я надеюсь, вы понимаете, насколько это может быть полезно, когда вы решаете некоторые сложные вопросы.