Mocha & Power-assertでalexa-sdkで作ったAlexa Skillのユニットテスト
この記事は一人Alexa Skills Kit for Node.js Advent Calendar 2017の7日目の記事です。 alexa-conversationでAlexa Skillのテストをするという記事は […]
目次
この記事は一人Alexa Skills Kit for Node.js Advent Calendar 2017の7日目の記事です。
alexa-conversationでAlexa Skillのテストをするという記事は以前に書きましたが、今度はMocha & Power-assertでテストする方法です。
メリット
- eventの値を細かくシュミレートできる
- JS定番のやり方でテストできる
- CardやEcho Showのためのレスポンスなどもテストできる
デメリット
- eventの値を作るのが面倒
- callbackにアサーションを書くとハマる
eventの値をシュミレートする
AWS Lambdaのドキュメントにだいたいのイベントのサンプルが公開されていますが、Alexa Skillは例外です。
developer.amazon.comにある「
カスタムスキルのJSONインターフェースのリファレンス」から値をとってきましょう。
「自分のコードで使わないから、event = {}
とかでいいかなー」と思っていると、event.sessionがない
などいろいろ怒られることになるので要注意です。
テスト対象コードのサンプル
テスト用にいわゆるHello world的なコードを用意しました。
index.js
'use strict'
const Alexa = require('alexa-sdk')
const handlers = {
'LaunchRequest': function () {
this.emit(':tell', 'サンプルスキルへようこそ。')
}
}
module.exports.handler = (event, context, callback) => {
alexa = Alexa.handler(event, context, callback)
alexa.registerHandlers(handlers)
alexa.execute()
}
テストコード
tests/index.test.js
const assert = require('power-assert')
const MyLambdaFunction = require('../index.js')
const { handler } = MyLambdaFunction
// eventには
// https://developer.amazon.com/docs/custom-skills/request-and-response-json-reference.html
// の値をはりつけておく
const event = {
...
}
describe('LaunchRequest', () => {
it('Say hallo world', () => {
event.request.type = 'LaunchRequest'
const succeed = (data) => {
const { response } = data
const {
outputSpeech
} = response
assert.deepEqual(
outputSpeech,
{
type: 'SSML',
ssml: '<speak> サンプルアプリへようこそ。 </speak>'
}
)
}
const fail = (e) => {
if (e.name === 'AssertionError') {
assert.deepEqual(e.expected, e.actual)
} else {
assert.ok(false)
}
}
handler(event, {succeed, fail}, (error, data) => {})
})
})
テスト結果
1 failing
1) LaunchRequest
Say hallo world:
AssertionError: { type: 'SSML',
ssml: '<speak> サンプルスキルへようこそ。 </speak>' } deepEqual { type: 'SSML',
ssml: '<speak> サンプルアプリへようこそ。 </speak>' }
+ expected - actual
{
- "ssml": "<speak> サンプルスキルへようこそ。 </speak>"
+ "ssml": "<speak> サンプルアプリへようこそ。 </speak>"
"type": "SSML"
}
at Decorator._callFunc (node_modules/empower-core/lib/decorator.js:110:20)
at Decorator.concreteAssert (node_modules/empower-core/lib/decorator.js:103:17)
at Function.decoratedAssert [as deepEqual] (node_modules/empower-core/lib/decorate.js:51:30)
at Object.fail (test/unit/intent/HelpIntent.js:31:16)
at AlexaRequestEmitter.ValidateRequest (node_modules/alexa-sdk/lib/alexa.js:181:28)
at AlexaRequestEmitter.HandleLambdaEvent (node_modules/alexa-sdk/lib/alexa.js:121:25)
at AlexaRequestEmitter.value (node_modules/alexa-sdk/lib/alexa.js:95:31)
at module.exports.handler (index.js:7:9)
at exports.executeFunction (test/unit/intent/helpers.js:42:3)
at Context.it (test/unit/intent/HelpIntent.js:36:5)
Tips1: アサーションはcontext(第二引数)に
alexa-sdk
はcallback
ではなく、context.succeed
に成功結果を返します。
AWS Lambdaのドキュメントでは「callback
を使ってね」とありますので、そのノリでテストを書くと「あれ?」ってなります。
Tips2: context.failにもアサーションを書く
また、context.succeed
でアサーションがFailするとcontext.fail
が呼び出されます。
なのでアサーションをcontext.succeed
に書きつつ、アサーションが失敗した場合(AssertionError
)はcontext.fail
の方でハンドリングしてやらないと、期待したメッセージが出なかったりテストをパスさせてしまったりします。
その他
今回は発話部分(data.response.outputSpeech
)のテストをしていますが、Amazon Echo向けのレスポンスdata.response.directives
やAlexa APP向けの表示data.response.card
のテストなどを書く様にするとかなり便利な気がします。