🤔
特定のメソッドのみをMock化してテストコードを書く
はじめに
Pipeline上でAPIのテストを行う際に、DBへのアクセスなどがある場合、そのアクセスにより低速になり応答によって、実行結果が変わってしまうのは不適切でパイプラインが失敗してしまう原因になります。
そのため、外部リソースにアクセスする代わりに、Mockとして応答を偽のデータに置き換えることで、高速なテスト実行ができます。
今回はNode.jsで作成されたAPIに対して、Jestを利用してDBアクセスする部分をMock化したので、紹介しようと思います。
ドキュメントにはモック関数のmockImplementationOnce
メソッドを利用する方法などが記載されていますが、こちらはクラス丸ごとのモック化で利用できます。
しかし、今回は特定のメソッドをMock化したかったため、別の方法を採用しました。
環境
- Jest: 26.4.0
- Node.js: v12.18.3
Mockする関数
今回は顧客のAPIがあったとします。関数としては検索用のsearchしか記載していませんが、他にもレコード作成のcreateやdeleteなどがあるとします。
このAPIのGETリクエストのハンドリングで、ContactController.searchが実行されるように、別途routes.jsなどを実装します。
CustomerController.js
'use strict';
const ContactService = require('../services/ContactService');
module.exports = {
search: async ctx => {
try {
ctx.body = await ContactService.search(searchCriteria);
} catch (error) {
console.log(error);
}
}
CustomerService.js
'use strict';
const MODEL_NAME = 'contact';
module.exports = {
search: (criteria) => {
// DBへのアクセスなどがある(Promiseを返す)
return service.db.search(MODEL_NAME, criteria);
}
Mockの実装
テストコードは以下です。
index.test.js
const CustomerService = require('../service/CustomerService');
describe('Customers: get', () => {
beforeAll(async () => {
jest.spyOn(CustomerService, 'search').mockImplementation(
(criteria) => {
if (criteria.name === 'test') {
return Promise.resolve([
{ id: 'uuid', name: 'test' }
{ id: 'uuid', name: 'test2'}
]);
}
}
);
});
test('getCustomer', async done => {
//実際のテストコード
});
})
Mock関数の実装にはjest.spyOn()
メソッドを利用することで、実現しています。
- Mock化するモジュールの読み込み
- Mock化するメソッドのみを
jest.spyOn
でMock化する。- もとの関数が引数によって、複数パターンの返り値がほしい場合は、if分岐などで記載できる。(criteria部分)
- MockはbeforeAllでやっていますが、testのところで実装することも可能です。
おわりに
Jestを使えば、特定のメソッドのみをMock化することが簡単にできました。Jestでテストコードを書くことは比較的簡単に書けて、アサートなどもシンプルにかけるので、便利だと感じました。
もし、理解が間違っている部分などあれば、遠慮なく指摘ください。
Discussion