[JavaScript, TypeScript] Пишем юнит тесты на TypeScript'е (на примере котиков)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
19-Апр-2021 20:31


Как писать модульные тесты в проекте с TypeScript'ом? В этой статье я постараюсь ответить на этот вопрос а также покажу как создать среду модульного тестирования под проекты использующие TypeScript.Юнит тесты, что это?Unit tests ( модульные тесты) - тесты применяемые в различных слоях приложения, тестирующие наименьшую делимую логику приложения: например модуль, класс или метод.Суть юнит тестов, в том чтобы писать их к каждому новому классу или методу, проверяя, не привело ли очередное изменение кода к появлению ошибок (багов) в уже протестированных местах программы.Отсюда следует что юнит тесты должны быть быстрыми. Такие тесты могут выполнятся часто, во время программирования. Т.е разработчик после написания нового класса или метода, пишет пакет тестов к ним, затем запускает их вместе с уже имеющимся тестам остальных частей программы. На выходе получаем код покрытый тестами что позволяет избегать багов уже на старте разработки. Настройка окруженияИтак теперь ближе к делу. Предположим у нас есть некий проект со следующей структурой:
project
| node_modules
| src
| package.json
| tsconfig.json
В ./src лежит некий модуль cat.module.ts который содержит простой класс Cat.
export class Cat {
  public name: string;
  public color: string;
  constructor(name: string, color: string) {
    this.name = name;
    this.color = color;
  }
  public move(distanceMeter: number) : string {
    return `${this.name} moved ${distanceMeter}m.`;
  }
  public say() : string {
    return `Cat ${this.name} says meow`;
  }
}
Как видно, наш класс содержит в себе конструктор который принимает в себя значения имени и цвета а также пару методов. Этот класс и будет являтся нашим объектом тестирования (SUT - system under test).Создадим в корне проекта, папку test, в которой будем хранить наши тесты.Далее установим необходимые npm пакеты:npm install --save-dev ts-node mocha @testdeck/mocha nyc chai @types/chaiКраткое описание пакетов:
ts-node - пакет для исполнения TypeScript и REPL в среде node.js.mocha - популярный, гибкий тестовый фреймворк, позволяет разрабатывать тесты любого уровня. Будем использовать его как основу наших тестов. Вместе с ним используем @testdeck/mocha - имплементацию декоратора testdeck для Мокки, чтобы писать наши тесты в ООП стиле.nyc - современный CLI популярной утилиты Istanbul, которая расчитывает текущее покрытие тестами кода.chai - популярная библиотека для проверки утрверждений(assertions), подходит для многих тестовых фреймворков. Мы же будет ее использовать в паре с Моккой. Добавим так же @types/chai чтобы наш чаи мог свободно работать с типами typescript'аПосле установки всех необходимых пакетов, создадим в нашей папке test, файл tsconfig.json, в который добавим конфиги TS которые будут вызыватся отдельно для наших тестов.
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "baseUrl": "./",
    "module": "commonjs",
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "isolatedModules": false,
    "strict": false,
    "noImplicitAny": false,
    "typeRoots" : [
      "../node_modules/@types"
    ]
  },
  "exclude": [
    "../node_modules"
  ],
  "include": [
    "./**/*.ts"
  ]
}
В строчке include мы указываем включать все файлы в папке test с расширешием .tsЗатем создадим в корне проекта, файл register.js в котором опишем иснтрукции для ts-node, откуда запускать и транспилировать наши тесты.
const tsNode = require('ts-node');
const testTSConfig = require('./test/tsconfig.json');
tsNode.register({
  files: true,
  transpileOnly: true,
  project: './test/tsconfig.json'
});
Далее создадим там в корне, файл .mocharc.json, со следующим содержимым:
{
  "require": "./register.js",
  "reporter": "list"
}
И файл .nyrc.json с конфигом нашей утилиты для анализа тестового покрытия.
{
  "extends": "@istanbuljs/nyc-config-typescript",
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules/"
  ],
  "extension": [
    ".ts"
  ],
  "reporter": [
    "text-summary",
    "html"
  ],
  "report-dir": "./coverage"
}
После добавления всех необходимых конфигов, дерево нашего проекта будет выглядить следующим образом:
project
| node_modules
| src
| test
| --- tsconfig.json
| .mocharc.json
| .nyrc.json
| package.json
| register.js
| tsconfig.json
Теперь необходимо добавить скрипт запуска в package.json
"test": "nyc ./node_modules/.bin/_mocha 'tests/**/*.test.ts'"
С настройкой закончили, теперь можно написать первый тестПишем тестыСоздаем файл в папке ./test файл cat.unit.test.ts и пишем в нем следующий код:
import { Cat } from '../src/cat.module';
import { suite, test } from '@testdeck/mocha';
import * as _chai from 'chai';
import { expect } from 'chai';
_chai.should();
_chai.expect;
@suite class CatModuleTest {
  private SUT: Cat;
  private name: string;
  private color: string;
  before() {
    this.name = 'Tom';
    this.color = 'black';
    this.SUT = new Cat(this.name, this.color);
  }
}
Сейчас мы импортировали наш класс Cat из модуля cat.module.ts, добавили импорты необходимых тестовых библиотек, а также создали необходимые переменные чтобы инициализировать наш класс.В секции before задали параметры необходимые для класс и создали инстанст класса Cat, на котором будут проходит тесты.Теперь добавим первый тест, проверяющий что наш кот существует и имеет имя которое мы ему задали.
import { Cat } from '../src/cat.module';
import { suite, test } from '@testdeck/mocha';
import * as _chai from 'chai';
import { expect } from 'chai';
_chai.should();
_chai.expect;
@suite class CatModuleTest {
  private SUT: Cat;
  private name: string;
  private color: string;
  before() {
    this.name = 'Tom';
    this.color = 'black';
    this.SUT = new Cat(this.name, this.color);
  }
  @test 'Cat is created' () {
    this.SUT.name.should.to.not.be.undefined.and.have.property('name').equal('Tom');
  }
}
Запускаем тест командой npm test и получаем примерно такой результат в консоле:
Как видим покрытие у нас не полное, остались не протестированными строчки 11-15. Это как раз методы класса Cat move и say. Дописываем еще два теста для этих методов и получаем в итоге такой файл с тестами:
import { Cat } from '../src/cat.module';
import { suite, test } from '@testdeck/mocha';
import * as _chai from 'chai';
import { expect } from 'chai';
_chai.should();
_chai.expect;
@suite class CatModuleTest {
  private SUT: Cat;
  private name: string;
  private color: string;
  before() {
    this.name = 'Tom';
    this.color = 'black';
    this.SUT = new Cat(this.name, this.color);
  }
  @test 'Cat is created' () {
    this.SUT.name.should.to.not.be.undefined.and.have.property('name').equal('Tom');
  }
  @test 'Cat move 10m' () {
    let catMove = this.SUT.move(10);
    expect(catMove).to.be.equal('Tom moved 10m.');
  }
  @test 'Cat say meow' () {
    expect(this.SUT.say()).to.be.equal('Cat Tom says meow');
  }
}
Снова запускаем наши тесты и видим что теперь класс Cat имеет полное тестовое покрытие.
ИтогПо итогу мы создали тестовую инфраструктуру для нашего приложения и теперь можем покрывать тестами любой новый модуль или класс, проверяя что существующий код не сломался.PS: Написано по мотивам статьиHow setting up unit test with TypeScript.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_javascript, #_typescript, #_unit_test, #_typescript, #_javascript, #_typescript
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 18:58
Часовой пояс: UTC + 5