Введение

Angular 2, как правило, является одним из самых популярных интерфейсных фреймворков в последнее время. Мы решили попробовать и теперь собираемся поделиться мыслями на эту тему. Вы можете найти в Интернете отличные статьи о том, как создавать свои первые компоненты, или даже более сложные темы, но мы обнаружили, что этого недостаточно для создания большого масштабируемого приложения (например, приложений LiveChat).

Возвращаясь к истории, одной из причин, по которой был представлен Angular 1, была проблема тестирования интерфейсных приложений. Он довольно хорошо решил эту проблему, и версия 2 следует этому пути, несмотря на то, что это совершенно новый фрагмент кода.

Что делает его хорошим, так это разделение интересов. Модульное тестирование (которое будет рассмотрено здесь) предназначено для проверки того, что каждая отдельная функция системы работает совершенно нормально, даже не зная о какой-либо другой части. Если выбранный фреймворк (или библиотека) не помогает с таким разделением и не дает возможности мокить зависимости, то со временем сделать это правильно будет очень сложно (а может, и невозможно).

Angular 2 легко тестируется — это правда, но на данный момент существует огромная нехватка ресурсов по этой теме (поскольку мы сейчас находимся в бета-версии 1!). Вот почему мы хотим поделиться своими знаниями по этой теме и начать дискуссию.

Типскрипт или нет?

Как некоторые из вас помнят, тестирование AngularJS на самом деле сводилось к следованию правилам, установленным командой Angular, и использованию их способов имитации, внедрения и т. д. Подобные вещи применимы к новой версии, но не в такой степени. Дело в том, что Angular 2 интенсивно использует функции ECMAScript 2015/2016, и все части приложения ng2 теперь являются классами JS. Каков результат? Теперь его можно протестировать на чистом JS (в некоторой степени). Кажется милым? Тогда начнем.

Отказ от ответственности: код здесь написан на Angular 2 с использованием TypeScript и Jasmine в качестве среды тестирования. Хотя первый тест можно выполнить на чистом JavaScript, последние будут использовать TypeScript для более тесной интеграции с Angular 2. Это означает, что лучше сначала настроить тестовую среду, а затем постепенно переходить к более сложным тестам. Если у вас его еще нет, вы можете взять тот, над которым я работаю, здесь: https://github.com/wkwiatek/angular2-webpack2.

Первые тесты

Примечание. Статья основана на бета-версии 2 Angular 2.

Суть с примерами для всей серии (проверено на бета-версию 16) находится здесь: Суть тестирования Angular 2

Начало — первый компонент — Приложение. Все приложения Angular 2 состоят из компонентов, поэтому все приложение также является компонентом. Это может выглядеть так:

import {Component} from 'angular2/core';

@Component({
  selector: 'app',
  template: '<span>Hello</span>'
})
export class App {}

По сути, это класс с декоратором, который добавляет некоторую логику, используемую Angular. Важно то, что декораторы добавляют кое-что в класс. Это означает, что мы все еще можем сделать: new App() и использовать чистый JS-объект.

Добавим свойство:

@Component({
  selector: 'app',
  template: '<span>{{hello}}</span>'
})
export class App {
  private hello: string = 'Hello';
}

А теперь перейдем к тестам. Мое личное предпочтение (и то, которое мы используем в LiveChat) состоит в том, чтобы тесты были как можно ближе к коду. Когда у нас есть такой файл, как app.ts, который содержит код из приведенного выше фрагмента, мы создадим файл с именем app.spec.ts и поместим туда следующие вещи:

и поместите туда следующие вещи:

import {App} from './app';
describe('App', () => {
  beforeEach(function() {
    this.app = new App();
  });
  it('should have hello property', function() {
    expect(this.app.hello).toBe('Hello');
  });
});

Примечание. Хорошо сначала написать неудачные тесты, а затем сделать их пройденными, даже если TDD не введен. Это просто о том, чтобы убедиться, что конкретный тест выполняется и не дает ложного срабатывания. В Jasmine очень часто можно увидеть выражение вроде expect(...).not.toBe(...).

Простой? Я полагаю, да. И ага-момент: теперь мы можем тестировать Сервисы, Трубы, базовые Компоненты и все, что является классом JS!

Хотите протестировать какой-то метод в компоненте? Вот:

@Component({
  selector: 'app',
  template: '<span>{{sayHello()}}</span>'
})
export class App {
  private name: string = 'John';
  sayHello(): string {
    return `Hello ${this.name}`;
  }
}
import {App} from './app';
describe('App', () => {
  beforeEach(function() {
    this.app = new App();
  });
  it('should have name property', function() {
    expect(this.app.name).toBe('John');
  });
  it('should say hello with name property', function() {
    expect(this.app.sayHello()).toBe('Hello John');
  });
});

Примечание. Здесь мы используем старый добрый анонимный function(). Это потому, что мы используем разницу между ней и стрелочной функцией — контекст. Каждый function получает свой контекст из кода, из которого он был вызван. Таким образом, this в тесте с жасмином одинаково для разных комбинаций beforeEach, it и afterEach.

Слишком легко для вас? Оставайтесь с нами в следующей части, когда я расскажу о внедрении зависимостей и тестах компонентов с помощью DOM.

Автор поста: Войцех Квятек

Это сообщение изначально было опубликовано в Блоге разработчиков LiveChat.