эпики модульного тестирования при использовании redux-observable
В моем последнем посте я говорил о том, что такое промежуточное ПО, наблюдаемое за редукцией, и как вы можете применить его для решения практических задач (автосохранение).
В этом посте я покажу вам, как легко и весело провести эпическое модульное тестирование! (это и все дальнейшие каламбуры полностью предназначались) Напоминаем, что примерно так выглядел пользовательский интерфейс в предыдущем посте, в то время как эпик saveFieldEpic.js
прислушивался к действиям, отправленным из события onChange
этого компонента ввода. :
Перед тем, как мы начнем писать код для наших тестов, мы можем упростить тестирование, добавив зависимости во все эпики (которые мы захотим заменить позже в наших тестах) при объединении эпиков, прямо перед вызовом createEpicMiddleware
(полный кредит на Джею Фелпсу за эту информацию!).
const rootEpic = (...args) => combineEpics( saveFieldEpic, )(...args, {ajax});
В этом примере, когда мы создаем хранилище Redux, мы вводим ajax
из rxjs/observable/dom/ajax
, который теперь будет отображаться как третий аргумент в наших эпиках (сразу после action$
и store
). Опять же, это сделано для того, чтобы мы могли заменить ее другой функцией во время тестирования, которая фактически не будет отправлять XHR по сети.
Код в нашем saveFieldEpic.js
файле из последнего сообщения теперь будет выглядеть примерно так: мы передаем action$
в строке 14, как обычно, затем null
для значения store
(поскольку оно нам не понадобится) и, наконец, {ajax}
.
* примечание: использование null
для значения хранилища может привести к ошибкам сборки, и в этом случае вы можете просто использовать store
(обновлено 23 ноября 2017 г.)
Теперь, когда мы внедрили зависимость AJAX и наша эпическая программа уже работает изолированно, мы можем приступить к тестированию входных и выходных данных самой эпической функции (без необходимости имитировать хранилище).
Импортируя ActionsObservable
из библиотеки, наблюдаемой за redux, мы можем отправлять имитирующие действия в тестируемую эпопею. Затем мы можем создать нашу фиктивную версию функции AJAX, которая будет либо возвращать Observable.of({})
(или любой другой тип ответа сервера), если вызов AJAX должен быть успешным, либо Observable.throw('something bad!')
, если вызов AJAX должен завершиться неудачно.
Наконец, мы импортируем эпос, скармливаем ему эти входные данные и вызываем toArray
, чтобы, когда мы подписываемся на выход эпика, он возвращал массив всех действий, произведенных эпосом, в качестве выходных данных! Утверждение, что actualOutputActions
глубоко равно expectedOutputActions
, дает нам возможность пройти тесты!
Вот как это будет выглядеть в коде:
Я считаю эту простоту прекрасной вещью! Я также обнаружил, что этот метод остается сверхмощным при использовании в еще более сложных сценариях. И, что не менее важно, писать эти тесты - это тонна удовольствия. 🚀