Тестируем Angular приложение. Часть 1. Тестирование компонента (+ EventEmitter)

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

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

Вступление

По умолчанию, Angular предлагает средства для тестирования приложенния, такие как Karma, Jasmine, Protractor. В данной статье будем использовать связку из коробки Karma + Jasmine. Karma это так называемый тест раннер который позволяет нам настраивать то на каких устройствах или браузерах будут запускатся тесты и какие тестовые фреймворки и плагины, будут участвовать в тестах. Jasmine это BDD фрейворк для тестирования javascript кода.

Начальное приложение

Имеем обычное стартовое приложение my-app для примера с созданным компонентом Hello (в моем примере, ни app и hello компоненты не имеют предсоздаваемого автоматически файла .spec.ts). В корне нашего приложения имеется так же предсозданный файл karma.conf.js (создается автоматически при генерации приложения через Angular CLI). В нем находится конфиг нашего тест раннера. Подробно его разбирать в рамках статьи не будем. В кратце только скажу что здесь задаются настройки того, в каком браузере будет запускатся окно тест раннера (по умолчанию стоит Chrome), какие плагины подключать, и на каком порту запускать тест раннер (по умолчанию порт 9876). В src/app лежит наш тестируемый компонент Hello, который выглядит следующим образом:

import { Component, OnInit, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-hello',
  templateUrl: './hello.component.html',
  styleUrls: ['./hello.component.scss']
})
export class HelloComponent implements OnInit {

  @Output() colorEmitter = new EventEmitter<string>();

  color: string = '';
  //countries = [];

  constructor() { }

  ngOnInit(): void {
  }

  sayHello(name: any) {
    return `Hello ${name}`;
  }
  
  giveLangCode() {
    return ['ru', 'en', 'ua'];
  }

  setColor() {
    this.color = 'Black';
    this.colorEmitter.emit(this.color);
  }
}

Компонент простой и состоит из нескольких методов, первый sayHello принимает имя и возвращает строковое значение приветствия, второй giveLangCode возвращает массив значений. Третий метод setColor присваивает значение цвета переменной и "эмиттит" его значение.

Создание spec файла и запуск Karma

С компонентом определились, теперь создадим файл hello.spec.ts в папке с компонентом и добавим в него следующее содержимое:

import { HelloComponent } from "./hello.component"

describe('HelloComponent', () => {

  let hello: HelloComponent;
  
});

Тут мы экпортировали наш тестируемый компонент Hello и добавили функцию обертку describe для нашего тестового набора а также объявили переменную hello для инициализации нашего компонента.

Теперь запустим Karma командой ng test. Откроется окно браузера с открытым тест раннером на порте 9876.

Так как сами тесты мы еще не добавили то и отчета об их прохождении, в окне не будет. Осталяем запущенным тест раннер и приступаем к написанию тестов.

Добавление тестов

Возвращаемся в наш файл hello.spec.ts и через конструкцию beforeEach добавляем инициализацию компонента для каждого теста (это создаст изолированность наших тестов друг от друга).

import { HelloComponent } from "./hello.component"

describe('HelloComponent', () => {

  let hello: HelloComponent;

  beforeEach(() => {
    hello = new HelloComponent();
  });
  
});

Затем через конструкцию it добавлем тест нашего первого метода sayHello

import { HelloComponent } from "./hello.component"

describe('HelloComponent', () => {

  let hello: HelloComponent;

  beforeEach(() => {
    hello = new HelloComponent();
  });

  it('should say hello Tom', () => {
    expect(hello.sayHello('Tom')).toBe('Hello Tom');
  });

});

Тут все просто, тест вызывает метод sayHello и передает тестовое значение в качестве аргумента, затем проверяет что в ответе приходит то что должен возвращать метод.

Проверям окно тест раннера и наш тест должен появится в отчете с успешным статусом.

Теперь напишем второй тест для метода giveLangCode в котором проверим содержание всех трех значений возращаемого массива.

import { HelloComponent } from "./hello.component"

describe('HelloComponent', () => {

  let hello: HelloComponent;

  beforeEach(() => {
    hello = new HelloComponent();
  });

  it('should say hello Tom', () => {
    expect(hello.sayHello('Tom')).toBe('Hello Tom');
  });

  it('should country codes is ru en ua', () => {
    const countries = hello.giveLangCode();
    expect(countries).toContain('ru');
    expect(countries).toContain('en');
    expect(countries).toContain('ua');
  });

});

Проверяем окно тест раннера и видим что второй тест тоже успешно пройден.

Дополнительно можно добавить еще проверки для переменных компонента которые объявляются вначале,такие как проверка значения и типа (toEqual, toBeInstanceOf). Более подробно можно почитать в документации к Jasmine.

Тест EventEmitter'a (бонус)

У нас остался не покрыт тестами, метод setColor. Сам метод просто задает значение переменной color, затем обращается к colorEmitter и передает родительским компонентам, значение переменной color. Напишем тест который проверит что действительно значение переменной передается "наверх" родителям.

import { HelloComponent } from "./hello.component"

describe('HelloComponent', () => {

  let hello: HelloComponent;

  beforeEach(() => {
    hello = new HelloComponent();
  });

  it('should say hello Tom', () => {
    expect(hello.sayHello('Tom')).toBe('Hello Tom');
  });

  it('should country codes is ru en ua', () => {
    const countries = hello.giveLangCode();
    expect(countries).toContain('ru');
    expect(countries).toContain('en');
    expect(countries).toContain('ua');
  });

  it('should color event is Black', () => {
    let result = '';
    hello.colorEmitter.subscribe(v => result = v);
    hello.setColor();
    expect(result).toBe('Black')
  });
});

Тут тест вызывает наш эмиттер и подписывается на его значение, которое помещается в переменную result (объявили ее в начале теста, как пустую строку). Затем тест, вызывает метод setColor и проверяет что наш результат(result) изменился c пустой строки на то которое присваивается внутри метода setColor (в нашем случае 'Black').

Проверяем наш тест раннер и видим что наш тест прошел успешно. Таким образом видим что наш colorEmitter работает корректно.

Заключение

В этой статье мы расмотрели варианты тестирования компонента с методами, возвращающими различные типы данных и протестировали EventEmitter. В следующей части, займемся тестированием сервисов и форм.

Источник: https://habr.com/ru/post/575644/


Интересные статьи

Интересные статьи

В продолжении предыдущей статьи о том, какие изменения претерпевают бизнесы, в этой я углубляюсь именно в сферу IT и изменения в IT компаниях. В это время ряд IT-компаний оказываются в...
Вторая часть перевода статьи Леона Старра, инженера программных моделей. Первая часть вот здесь. В этой части — о семантике и о том, что отличает хорошую модель. Читать...
Исторически утилиты командной строки в Unix-системах развиты лучше чем в Windows, однако с появлением нового решения ситуация изменилась. Читать дальше →
О методике мы рассказывали в первой части статьи, в этой мы тестируем HTTPS, но в более реалистичных сценариях. Для тестирования был получен сертификат Let’s Encrypt, включено сжатие Brotli н...
Привет Хабр. В предыдущей части было рассмотрено декодирование сигналов RDS для FM-радиостанций, и идея следующей статьи возникла сама собой — нужно сделать свой собственный FM-трансмиттер. ...