エンジニアの育成をはじめました
IT
PR

Expressでテストを実行させる方法

Ryota Sugaya
記事内に商品プロモーションを含む場合があります

今回はNode.jsのフレームワーク「Express」を使って単体テストを実行していく過程をお見せします。

テストフレームワークは「Jest」を使っていきます。最終的にはgithub Actionsを使ってテストを実行できるようにします。

この記事を見ればExpressでテストを実行できるようになります。

スポンサーリンク

Expressとは

ExpressはWebアプリケーション開発する上で効率化するためのフレームワークです。

Expressで使った具体例としてAPI開発があります。リクエストに対して処理をしてレスポンスとして返すようにするWebアプリケーションを作ることができます。

Jestとは

JestはJavaScriptのテストフレームワークであり、Jestは使いやすく高速なテストが実行できます。モックやスパイの作成が簡単にできテストを効率化をすることができます。

Expressでテストを実行させる方法

  1. 必要なライブラリをインストールする
  2. package.jsonを設定する
  3. テストコードを作成する
  4. ロジックコードを作成する
  5. テストが通ることを確認する
  6. github Actionsで実行させる

1.必要なライブラリをインストールする

npm install jest supertest axios dotenv express log4js

2.package.jsonを設定する

{
・・・
    "main": "server.js",
    "scripts": {
        "start": "node server.js",
        "test": "jest"
    },
・・・
}

3.テストコードを作成する

下記のテストコードは「api/root」でリクエストした際のAPIのレスポンスのテストです。

const mockFn = jest.fn();
const request = require('supertest');
const app = require('../app.js');

const address = require('../src/common/address.js');
const spyAddressSearch = jest.spyOn(address, 'search');

const path = '/api/root';

jest.setTimeout(10000);
describe('正常', () => {
    test('レスポンス確認', async () => {
        spyAddressSearch.mockImplementationOnce(() => {
            return {
                results: [
                    {
                        address1: '東京都',
                        address2: '千代田区',
                        address3: '飯田橋',
                        kana1: 'トウキョウト',
                        kana2: 'チヨダク',
                        kana3: 'イイダバシ',
                        prefcode: '13',
                        zipcode: '1020072',
                    },
                ],
                status: 200,
            };
        });
        const result = await request(app)
            .get(path)
            .query({ id: 'ezaki', postCode: '1020072' });

        expect(result.statusCode).toBe(200);
        expect(result.body).toStrictEqual({
            id: 'ezaki',
            address: {
                results: [
                    {
                        address1: '東京都',
                        address2: '千代田区',
                        address3: '飯田橋',
                        kana1: 'トウキョウト',
                        kana2: 'チヨダク',
                        kana3: 'イイダバシ',
                        prefcode: '13',
                        zipcode: '1020072',
                    },
                ],
                status: 200,
            },
        });
    });
});

下記のテストコードは「address.js」で郵便番号検索する際のテストコードです。

const mockFn = jest.fn();
jest.mock('axios', () => {
    return {
        create: jest.fn(() => ({
            get: mockFn,
        })),
    };
});
const address = require('../../src/common/address');

jest.setTimeout(10000);
describe('正常', () => {
    test('レスポンス確認 ハイフンなし', async () => {
        mockFn.mockResolvedValue({
            status: 200,
            data: {
                results: [
                    {
                        address1: '東京都',
                        address2: '千代田区',
                        address3: '飯田橋',
                        kana1: 'トウキョウト',
                        kana2: 'チヨダク',
                        kana3: 'イイダバシ',
                        prefcode: '13',
                        zipcode: '1020072',
                    },
                ],
                status: 200,
            },
        });
        const postCode = '1020072';
        const result = await address.search(postCode);
        expect(result.status).toBe(200);
        expect(result.results).toStrictEqual([
            {
                address1: '東京都',
                address2: '千代田区',
                address3: '飯田橋',
                kana1: 'トウキョウト',
                kana2: 'チヨダク',
                kana3: 'イイダバシ',
                prefcode: '13',
                zipcode: '1020072',
            },
        ]);
    });

    test('レスポンス確認 ハイフンあり', async () => {
        mockFn.mockResolvedValue({
            status: 200,
            data: {
                results: [
                    {
                        address1: '東京都',
                        address2: '千代田区',
                        address3: '飯田橋',
                        kana1: 'トウキョウト',
                        kana2: 'チヨダク',
                        kana3: 'イイダバシ',
                        prefcode: '13',
                        zipcode: '1020072',
                    },
                ],
                status: 200,
            },
        });
        const postCode = '102-0072';
        const result = await address.search(postCode);
        expect(result.status).toBe(200);
        expect(result.results).toStrictEqual([
            {
                address1: '東京都',
                address2: '千代田区',
                address3: '飯田橋',
                kana1: 'トウキョウト',
                kana2: 'チヨダク',
                kana3: 'イイダバシ',
                prefcode: '13',
                zipcode: '1020072',
            },
        ]);
    });
});

4.テストコードを元にロジックコードを作成する

通常はapp.jsの中にポートの情報を記載しますがJestを実行するとエラーになってしまうためソースコードを分割にします。

const app = require('./app');
require('dotenv').config();

const env = process.env;
const port = env.PORT;

app.listen(port, () => {
    console.log(`Listening on port ${port}`);
});

routerの設定も行います。

require('dotenv').config();

const express = require('express');
const app = express();
const router = express.Router();
const rootRouter = require('./src/root');

app.use('/api/root', rootRouter);
app.use('/', router);
app.use(express.json());

module.exports = app;

ここから実際のロジックを記載していきます。

まずは「root.js」からです。

const express = require('express');
const router = express.Router();
const log = require('./common/log');
const address = require('./common/address');

router.get('/', async (req, res) => {
    const systemLogger = log.getLogger();
    systemLogger.debug(req.query);

    let addressResult = {};
    if (req.query.postCode) {
        addressResult = await address.search(req.query.postCode);
        systemLogger.debug('addressResult:' + addressResult);
    }

    res.status(200).send({
        id: req.query.id,
        address: addressResult,
    });
});

module.exports = router;

次に「address.js」です

const log = require('./log');
const axiosBase = require('axios');
const axios = axiosBase.create({
    timeout: 2000,
    headers: {},
    defaults: {},
});

exports.search = async (zipcode) => {
    const systemLogger = log.getLogger();
    let getData;
    try {
        await axios
            .get(`http://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipcode}`)
            .then((res) => {
                if (res && res.status === 200) {
                    systemLogger.debug(res.data.results[0]);
                    getData = res.data;
                }
            })
            .catch((error) => {
                systemLogger.fatal(error.stack);
            });
    } catch (e) {
        systemLogger.fatal(e.stack);
    }
    return getData;
};

5.テストが通ることを確認する

下記のコマンドを実行してJestを起動します

npm run test

すべてpassedになっていればテストが通っています。

6.github Actionsで実行させる

下記のコードをgithubに登録することで継続的にJestを実行させることができます。

name: ci

on:
    push:
        branches: [main]
    pull_request:
        branches: [main]

jobs:
    test:
        runs-on: ubuntu-latest
        steps:
            - name: Checkout
              uses: actions/checkout@v2

            - name: Setup Nodejs
              uses: actions/setup-node@v1
              with:
                  node-version: 14

            - name: Unit test
              run: |
                  npm install
                  npm test

githubに登録されると下記のように実行されます。

Jestでエラーがある場合は✕で表示され正常に終了した場合はチェックマークで表示されるので視覚的にわかりやすいと思います。

まとめ

今回はExpressでテストを実行させる方法について解説しました。

jestやgithub actionsを使ってCI/CDのCIの部分を効率化していきましょう。

今回のソースはこちらで公開しています。

ABOUT ME
Ryota Sugaya
会社員からフリーランスに転向 その後法人化し「合同会社NOA」を設立。 「合同会社NOAブログ」を運営中
スポンサーリンク
記事URLをコピーしました