[Node.js] sinon の stub を使う
Node.js のユニットテストが初めてで一苦労したのでまとめておきます。
目的
Node.js のユニットテストで Python でいうところの
をやりたい。
例えば AWS Lambda 関数で SSM および DynamoDB から値を取得する箇所があった場合、外部サービスとの結合なので実際に AWS にアクセスするのではなくモック化してテストを行いたいのです。
前提
環境
- Lambda ランライム Node.js 14.x
- aws-sdk 2.1215.0
- mocha 10.0.0
- power-assert 1.6.1
- proxyquire 2.1.3
- sinon 14.0.0
実装
Lambda
const aws = require('aws-sdk') const docClient = new aws.DynamoDB.DocumentClient() exports.handler = async (event) => { // SSM const { Parameters } = await (new aws.SSM()) .getParameters({ Names: ["SECRET_KEY_1", "SECRET_KEY_2"], WithDecryption: true, }) .promise() // DynamoDB const params = { TableName: process.env.TABLE_NAME, Key: { id: event.arguments.id } } const result = await docClient.get(params).promise() // 処理 return {} }
テストコード
'use strict' const assert = require('power-assert') const sinon = require('sinon') const proxyquire = require('proxyquire') describe('Test', () => { let lambda let proxyDynamoDB let proxySSM describe('#handler()', () => { beforeEach(() => { // hide lambda log sinon.stub(console, 'log').returns() sinon.stub(console, 'error').returns() // stub aws proxyDynamoDB = class { batchGet() { } get() { } query() { } put() { } delete() { } } proxySSM = class { getParameters() { } } // inject lambda = proxyquire('../index.js', { 'aws-sdk': { DynamoDB: { DocumentClient: proxyDynamoDB }, SSM: proxySSM, } }) // mock SSM getParameters sinon.stub(proxySSM.prototype, 'getParameters').returns({ promise: () => Promise.resolve({ Parameters: [ { Name: 'KEY_1', Value: 'DUMMY_VALUE_1', }, { Name: 'KEY_2', Value: 'DUMMY_VALUE_2', } ] }) }) process.env.TABLE_NAME = '' sinon.stub(process.env, 'TABLE_NAME').value('DUMMY_TABLE_NAME') const dynamoDbStub = sinon.stub(proxyDynamoDB.prototype, 'get') // mock DynamoDB get dynamoDbStub.withArgs({ TableName: process.env.TABLE_NAME, Key: { id: 'DUMMY_ID' } }).returns({ promise: () => Promise.resolve({ Item: { name: 'DUMMY_NAME', email: 'DUMMY_EMAIL', } }) }) }) it('テスト1', async () => { const event = { "requestContext": { "id": "DUMMY", } } await lambda.handler(event, context, () => { }).then( (data) => { assert.equal(data.isAuthorized, true) }, (err) => { # FIXME: Lambda で error 発生時にテスト失敗としたい。 # この書き方間違ってる気がするが、とりあえずテスト失敗には気がつける。 assert.equal(0, 1, 'test failed.') }) }) afterEach(() => { sinon.restore() }) }) })
テスト実施
$ npm i $ npm test
補足
下書きのまま長期間熟成した記事なので色々古いと思います。