Модульный тест и тест интеграции для AWS Lambda / NodeJS в TypeScript

Серия AWS Lambda / NodeJS (TypeScript)

  1. Как использовать TypeScript для AWS Lambda за 3 шага s
  2. Модульный тест и тест интеграции для AWS Lambda / NodeJS в TypeScript

Подготовка

Мы собираемся использовать jest для управления всеми тестами. Чтобы использовать jest с TypeScript, нам нужно будет установить некоторые babel зависимости. Пожалуйста, проверьте команды установки ниже:

// install jest and types
$ npm i -D jest @types/jest
// install babel support to use jest with typescript
$ npm i -D babel-jest @babel/core @babel/preset-env @babel/preset-typescript

Мы устанавливаем их в dev-dependencies, потому что они используются только во время тестирования, а не в окончательном собранном пакете. После установки нам нужно создать babel.config.js в, чтобы Babel работал. Содержание файла:

module.exports = {
    presets: [
        ['@babel/preset-env', {targets: {node: 'current'}}],
        '@babel/preset-typescript',
    ],
};

Теперь файловая структура выглядит так:

.
├── README.md
├── hello-world
│   ├── babel.config.js
│   ├── package-lock.json
│   ├── package.json
│   ├── src-ts
│   └── tsconfig.json
├── samconfig.toml
└── template.yaml

Модульный тест

Чтобы использовать jest, лучше всего иметь файл конфигурации, мы можем сгенерировать файл с jest cli:

// pwd: $ROOT/hello-world
$ ./node_modules/.bin/jest init // generate jest.config.js
$ mv jest.config.js jest.config.test.js // rename

В сгенерированном jest.config.test.js нам потребуются следующие параметры:

module.exports = {
  clearMocks: false,
  collectCoverage: true,
  coverageDirectory: "coverage",
  coverageProvider: "v8",

  testEnvironment: "node",
  testMatch: [
    "**/unit/**/*.test.ts"
  ],
};

Затем давайте создадим наш первый файл модульного теста hello-world/tests/unit/test-handler.test.ts. Далее мы могли заполнить файл модульным тестом для обработчика приложения, созданного в прошлой статье.

import { APIGatewayProxyEvent } from "aws-lambda";
import { lambdaHandler } from "../../src-ts/app";

describe('Unit test for app handler', function () {
    it('verifies successful response', async () => {
        const event: APIGatewayProxyEvent = {
            queryStringParameters: {
                a: "1"
            }
        } as any
        const result = await lambdaHandler(event)

        expect(result.statusCode).toEqual(200);
        expect(result.body).toEqual(`Queries: ${JSON.stringify(event.queryStringParameters)}`);
    });
});

Добавьте новую команду в package.json, чтобы мы могли легко запустить модульный тест:

"scripts": {
  "test": "jest --config=jest.config.test.js",
  "compile": "tsc"
}

Теперь у нас должна быть возможность запустить модульный тест и увидеть отчет о покрытии:

Выглядит отлично! Теперь файловая структура выглядит так:

.
├── README.md
├── hello-world
│   ├── babel.config.js
│   ├── jest.config.test.js
│   ├── package-lock.json
│   ├── package.json
│   ├── src-ts
│   ├── tests
│   │   └── unit
│   │       └── test-handler.test.ts
├── samconfig.toml
└── template.yaml

Интеграционный тест

Чтобы отличить интеграционный тест от модульного, нам понадобится другой файл конфигурации jest, а именно jest.confg.integ.test.js с содержимым:

// no need for coverage here
module.exports = {
  testEnvironment: "node",
  testMatch: [
    "**/integ/**/*.integ.test.ts"
  ],
};

Для запуска интеграционного теста нам потребуются еще две вещи:

  • Локальный сервер, на котором работает наша лямбда
  • Пакет HTTP SDK для отправки запроса на локальный сервер

Запустите лямбду на локальном сервере

К счастью, AWS SAM CLI предоставляет возможность запускать стек локально с помощью этой команды:

// pwd: $ROOT/hello-world
$ sam local start-api -t ../template.yaml

Эта команда требует установки Docker, вы можете обратиться к этому документу для получения дополнительной информации. После выполнения он вызовет сервер, прослушивающий 127.0.0.1:3000.

Лучше добавить эту команду и в скрипты NPM:

"scripts": {
  "test": "jest --config=jest.config.test.js",
  "start-local": "sam local start-api -t ../template.yaml",
  "compile": "tsc"
},

Добавить HTTP SDK в проект

Мы бы выбрали Axios для отправки запроса на сервер, запущенный выше:

$ npm i -D axios @types/axios

Создайте файл интеграционного теста hello-world/tests/integ/handler.integ.test.ts с содержанием:

import axios from "axios";

describe("Integration Test", () => {
    it("hello world integration test", async () => {
        const query = { a: "hi" };
        const response = await axios.get("http://localhost:3000/hello", {
            params: query
        });

        expect(response.status).toEqual(200);
        expect(response.data).toEqual(`Queries: ${JSON.stringify(query)}`);
    });
});

В этом интеграционном тесте мы используем axios для отправки GET сообщения серверу, запущенному выше. Более того, мы используем async и await, чтобы код теста оставался простым и читаемым.

Снова добавьте команду выполнения для интеграционного теста в package.json:

"scripts": {
  "test": "jest --config=jest.config.test.js",
  "integ-test": "jest --config=jest.config.integ.test.js",
  "start-local": "sam local start-api -t ../template.yaml",
  "compile": "tsc"
}

Запустите интеграционный тест

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

Окончательная файловая структура:

.
├── README.md
├── hello-world
│   ├── babel.config.js
│   ├── jest.config.integ.test.js
│   ├── jest.config.test.js
│   ├── package-lock.json
│   ├── package.json
│   ├── src-ts
│   │   └── app.ts
│   ├── tests
│   │   ├── integ
│   │   │   └── handler.integ.test.ts
│   │   └── unit
│   │       └── test-handler.test.ts
│   └── tsconfig.json
├── samconfig.toml
└── template.yaml

Заключение

Потрясающие! Теперь мы можем не только писать обработчики лямбда-выражений в TypeScript, но и составлять модульные / интеграционные тесты с помощью TypeScript. Полный код можно найти по адресу: https://github.com/zijing07/aws-lambda-nodejs-ts.

В следующей статье я расскажу, как создавать модульные / интеграционные тесты с помощью DDB в AWS Lambda.