QUnit и testing helpers

Ember.js активно использует QUnit в качестве тестового фреймворка для написания юнит-тестов и интеграционных тестов. QUnit позволяет легко создавать тесты, проверять их выполнение и предоставляет мощные инструменты для работы с асинхронным кодом. Встроенные testing helpers от Ember делают процесс тестирования ещё более удобным, предоставляя абстракции для взаимодействия с приложением, как если бы это делал пользователь.

Установка и настройка

QUnit уже интегрирован в проект Ember.js по умолчанию. Однако, для того чтобы начать писать тесты, нужно убедиться, что проект настроен корректно. В проекте Ember.js тесты обычно размещаются в директории tests/, а все тесты запускаются с помощью команды:

ember test

Эта команда запускает тесты, используя QUnit, и отображает результаты в терминале или браузере. Для создания нового теста можно воспользоваться генератором команд:

ember generate test <название теста>

Это создаст новый файл теста в папке tests/unit или tests/integration, в зависимости от типа теста.

Основы QUnit

QUnit использует функции для создания тестов: test() для определения теста и assert для утверждений внутри теста. Основная структура теста выглядит следующим образом:

test('название теста', function(assert) {
  let result = какая-то_функция();
  assert.equal(result, ожидаемое_значение, 'Описание ошибки');
});
  • assert.equal(actual, expected, message) — проверяет, что два значения равны.
  • assert.notEqual(actual, expected, message) — проверяет, что два значения не равны.
  • assert.ok(value, message) — проверяет, что значение является истинным.
  • assert.notOk(value, message) — проверяет, что значение является ложным.

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

Асинхронные тесты

В современных приложениях на Ember.js часто встречается асинхронный код. QUnit поддерживает асинхронные тесты с помощью функции assert.async(). Когда тест выполняет асинхронные операции, важно явно указать, когда тест завершён. Пример асинхронного теста:

test('проверка асинхронной функции', function(assert) {
  let done = assert.async();
  someAsyncFunction().then(function(result) {
    assert.equal(result, expected);
    done();
  });
});

Метод done() уведомляет QUnit о завершении асинхронного теста.

Ember Testing Helpers

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

visit()

visit() используется для имитации перехода пользователя по ссылке. Это помогает проверить поведение приложения после перехода на конкретный маршрут:

test('переход на главную страницу', async function(assert) {
  await visit('/');
  assert.equal(currentURL(), '/');
});

Функция visit() выполняет переход на маршрут, а currentURL() проверяет текущий URL после перехода.

click()

Функция click() позволяет имитировать клик по элементу на странице. Это полезно для тестирования взаимодействий с пользовательским интерфейсом:

test('клик по кнопке вызывает действие', async function(assert) {
  await visit('/');
  await click('.my-button');
  assert.ok(find('.result').text().includes('Ожидаемый результат'));
});

Здесь click() кликает по кнопке с классом .my-button, а затем проверяется, что на странице появился ожидаемый результат.

fillIn()

С помощью fillIn() можно заполнять поля ввода в формах. Это важно для тестирования взаимодействия с формами и валидации ввода данных:

test('заполнение формы', async function(assert) {
  await visit('/signup');
  await fillIn('#username', 'testuser');
  await fillIn('#password', 'password123');
  await click('button[type="submit"]');
  assert.equal(currentURL(), '/dashboard');
});

Функция fillIn() заполняет поля ввода указанными значениями, что позволяет проверить, как приложение реагирует на изменения в форме.

find()

Метод find() используется для поиска элементов на странице, что полезно для проверки наличия контента или изменения состояния DOM после выполнения действия:

test('проверка наличия текста на странице', async function(assert) {
  await visit('/');
  assert.ok(find('.welcome-message').text().includes('Добро пожаловать'));
});

andThen()

andThen() позволяет последовательное выполнение действий и проверок в тестах. Это полезно, когда необходимо выполнить несколько операций, ожидая завершения предыдущих:

test('переход между страницами', async function(assert) {
  await visit('/');
  await click('.about-link');
  andThen(function() {
    assert.equal(currentURL(), '/about');
  });
});

Работа с компонентами

Ember также предоставляет инструменты для тестирования компонентов. Чтобы протестировать компонент, можно использовать функцию this.render(). Пример теста компонента:

import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, click, find } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';

module('Integration | Component | my-component', function(hooks) {
  setupRenderingTest(hooks);

  test('кнопка изменяет состояние', async function(assert) {
    await render(hbs`<MyComponent />`);
    await click('.toggle-button');
    assert.ok(find('.status').text().includes('Активно'));
  });
});

Здесь используется render() для рендеринга компонента и find() для поиска текста в рендере компонента.

Управление состоянием приложения в тестах

Иногда в тестах нужно взаимодействовать с состоянием приложения, например, управлять роутами, контроллерами или моделями. Для этого Ember предоставляет несколько инструментов:

set()

Функция set() позволяет изменять свойства объектов, например, модели или контроллеров, что полезно для симуляции различных состояний приложения:

test('изменение состояния контроллера', async function(assert) {
  this.set('myController.property', 'new value');
  assert.equal(this.get('myController.property'), 'new value');
});

stubService()

Для тестирования сервисов можно использовать заглушки сервисов, которые позволяют подменить реальное поведение на имитацию. Это полезно, когда сервисы выполняют асинхронные операции или взаимодействуют с внешними API.

Советы по организации тестов

  • Разделение тестов по типам: Разделяйте тесты на юнит-тесты, интеграционные тесты и тесты компонентов. Это помогает поддерживать чистоту тестовой базы.
  • Использование fixtures: Для тестирования часто используемых данных можно использовать фикстуры, что позволит избежать повторяющегося кода.
  • Мокинг API: Для взаимодействия с внешними API используйте моки, чтобы не зависеть от внешних сервисов и сократить время выполнения тестов.

Заключение

QUnit и Ember testing helpers предоставляют мощный набор инструментов для эффективного тестирования приложений на Ember.js. Используя асинхронные тесты, взаимодействие с элементами страницы и проверки состояний приложения, можно обеспечить высокое качество и стабильность разрабатываемого кода. Важно грамотно организовать тесты и использовать предоставляемые Ember утилиты для максимальной эффективности работы.