Jestのモックを使ってインテント別にalexa-sdkで実装したコードをテストする
この記事は一人Alexa Skills Kit for Node.js Advent Calendar 2017の12日目の記事です。 alexa-sdkでコードを書く場合、以下のようなコードになります。 const A […]
目次
この記事は一人Alexa Skills Kit for Node.js Advent Calendar 2017の12日目の記事です。
alexa-sdkでコードを書く場合、以下のようなコードになります。
const Alexa = require('alexa-sdk')
const handlers = {
LaunchRequest: function () {
alexa.emit(':tell', 'Hello World!')
}
}
module.exports.handler = function (event, context, callback) {
const alexa = Alexa.handler(event, context)
alexa.registerHandlers(handlers)
alexa.execute()
}
これまで紹介したテストは、基本的にAWS Lambdaがコールするmodule.exports.handler
でテストをしていました。
今回はもうすこしスコープを小さく絞って以下の部分をテストしてみたいと思います。
LaunchRequest: function () {
alexa.emit(':tell', 'Hello World!')
}
テストできるように分割する
ぱっと見たところ問題点は2つあります。
- exportsされていないので
LaunchRequest()
をテストファイルからよべない this.emit
のようにthis
に依存している関数がある
ということでまずはこの2つを解消しましょう。
handlerを別ファイルに切り出す
とりあえずファイルを分割しましょう。
変更後のhandlers.js
module.exports = {
LaunchRequest: function () {
alexa.emit(':tell', 'Hello World!')
}
}
これで以下の例のようにLaunchRequest単体をよびだせるようになりました。
const handlers = require('handlers')
handlers.LaunchRequest()
変更後のindex.js
元ファイルの方も切り出したものをつかうように変更します。
const Alexa = require('alexa-sdk')
const handlers = require('handlers')
module.exports.handler = function (event, context, callback) {
const alexa = Alexa.handler(event, context)
alexa.registerHandlers(handlers)
alexa.execute()
}
ここでこれまで紹介したようなテストをまわしておくと、ちゃんと動くか確認できます。
「接合部」を作ってテスト可能なコードにする
このままではhandlers.LaunchRequest()
を実行しても、this.emit
がないというエラーが出るだけです。
ということでt_wadaさんのセッションを参考に「接合部」を作るようにします。
https://speakerdeck.com/twada/testable-lambda-working-effectively-with-legacy-lambda?slide=37
参考:Testable Lambda: Working Effectively with Legacy Lambda P.37
変更後のhandlers.js
LaunchRequestの中で実行するのではなく、makeResponse
関数にthisを渡してそちらで実行するようにしました。
同時にmakeResponse
についてもテストファイルからよめるようにexportしておきます。
const handlers = {
LaunchRequest: function () {
makeResponse(this)
}
}
function makeResponse (alexa) {
alexa.emit(':tell', 'Hello World!')
}
exports.handlers = handlers
exports.makeResponse = makeResponse
変更後のindex.js
exportの仕方が変わったため、こちらも変更しておきます。
const Alexa = require('alexa-sdk')
const libs = require('handlers')
module.exports.handler = function (event, context, callback) {
const alexa = Alexa.handler(event, context)
alexa.registerHandlers(libs.handlers)
alexa.execute()
}
これで準備ができました。
Jestでテストを書く
ここからはJestでテストを書いていきます。
LaunchRequest.test.js
ということで作成したものがこちらです。
/* global describe, it, jest, expect */
const handlers = require('./handlers')
describe('LaunchRequest', () => {
// emit()のモックを作成する
const mockAlexa = {
emit: jest.fn()
}
it('makeResponse()', () => {
handlers.makeResponse(mockAlexa)
// emit()が1度だけコールされていることをテストする
expect(mockAlexa.emit.mock.calls.length).toBe(1)
// emit()の引数が正しいものかをテストする
expect(mockAlexa.emit.mock.calls[0][0]).toBe(':tell')
expect(mockAlexa.emit.mock.calls[0][1]).toBe('Hello World!')
})
})
テストを実行する
あとはテストを実行するだけです。
$ ./node_modules/jest/bin/jest.js
PASS __tests__/LaunchRequest.test.js
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.504s
Ran all test suites.
おわりに
今回紹介した例では1行だけしかない関数のテストでしたが、外部のAPIと接続したり複雑な処理を走らせたい場合などに便利かなと思います。
Lambdaのhandlerを通してのテストの場合、eventの値をフルで渡す必要があったりcontext.succeed
とcontext.fail
のそれぞれにアサーションを書かないとだったりなので、手早くテストしたい場合にもおすすめです。