lambda-mocha-runnerでAlexaスキルの監視テスト
VUIアプリは見えないところで動作します。そのため、トラブルが起きていることを気づきにくいという問題があります。 ここでは、AWS Lambdaでユニットテストを実行し、AlexaのLambdaコードに問題が起きていない […]
広告ここから
広告ここまで
目次
VUIアプリは見えないところで動作します。そのため、トラブルが起きていることを気づきにくいという問題があります。
ここでは、AWS Lambdaでユニットテストを実行し、AlexaのLambdaコードに問題が起きていないかを確認する方法を紹介します。
テスト対象のコード
テストを実行するため、シンプルなスキルコードを用意します。
$ vim index.js
const Alexa = require('ask-sdk')
const skillBuilder = Alexa.SkillBuilders.standard()
const ExampleHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'
},
handle(handlerInput) {
return handlerInput.responseBuilder.speak('hello').getResponse()
}
}
module.exports.ExampleHandler = ExampleHandler
module.exports.handler = skillBuilder
.addRequestHandlers(ExampleHandler)
.addRequestHandler(
'TestIntent',
(handlerInput) => {
return handlerInput.responseBuilder.speak('goodby').getResponse()
})
.lambda()
準備
Serverless Frameworkでプロジェクトを作る
Serverless Frameworkでプロジェクトをセットアップします。
$ sls create -t aws-nodejs-ecma-script -p lambda-alexa-monitor
$ cd lambda-alexa-monitor
$ npm i
npmのライブラリを追加する
lambda-mocha-runner
というパッケージと関連のもろもろを追加します。
$ npm i -S lambda-mocha-runner ask-sdk mocha power-assert
lambda-mocha-runner
を追加することで、Lambda上でmochaのテストを実行できます。
テストファイルを作成する
テストコードを配置するディレクトリとファイルを用意します。
$ mkdir tests
$ touch tests/index.js
テストコードを書く
続いてテストのコードを用意します。
$ vim tests/index.js
const assert = require('power-assert')
const {
handler
} = require('../index')
// リクエストオブジェクトのモック
const event = {
session: {
new: true,
sessionId: 'amzn1.echo-api.session.[unique-value-here]',
attributes: {},
user: {
userId: 'amzn1.ask.account.[unique-value-here]'
},
application: {
applicationId: 'amzn1.ask.skill.[unique-value-here]'
}
},
version: '1.0',
request: {
locale: 'en-US',
timestamp: '2016-10-27T18:21:44Z',
type: 'LaunchRequest',
requestId: 'amzn1.echo-api.request.[unique-value-here]'
},
context: {
AudioPlayer: {
playerActivity: 'IDLE'
},
System: {
apiEndpoint: 'https://api.amazonalexa.com',
apiAccessToken: 'exampleAccessToken',
device: {
supportedInterfaces: {
AudioPlayer: {}
}
},
application: {
applicationId: 'amzn1.ask.skill.[unique-value-here]'
},
user: {
userId: 'amzn1.ask.account.[unique-value-here]'
}
}
}
}
// Promiseのラッパー
const invokeHandler = async (handler, event) => {
return new Promise((resolve, reject) => {
return handler(event, {}, (err, result) => {
if (err) return reject(err)
return resolve(result)
})
})
}
// テストを実行する
describe('test', () => {
it('test', async () => {
const r = await invokeHandler(handler, event)
assert.equal(r.response.outputSpeech.ssml, '<speak>hello</speak>')
})
})
テストの最終準備
最後にテストを実行するLambdaをセットアップします。
Define AWS Resource
まずAWSのリソースをserverless.yml
で定義します。
$ vim serverless.yml
service:
name: lambda-alexa-monitor
provider:
name: aws
runtime: nodejs6.10
functions:
# Lambda function for the Alexa Skill
target:
handler: index.handler
events:
- alexaSkill
# Lambda function to run the test
testAlexa:
handler: test.handler
events:
- schedule: cron(0/1 * * * ? *)
テストの実行関数を作成
そしてテストのコードを実行するためのコードを書きます。
$ vim test.js
const Runner = require('lambda-mocha-runner')
// eslint-disable-next-line import/prefer-default-export
class Lambda {
static run(event, c, callback) {
const context = {
mochaOptions: {},
testDir: './tests/'
}
return Runner.run(context)
.then(response => callback(null, response))
.catch(err => callback(err))
}
}
module.exports.handler = (event, context, callback) => {
return Lambda.run(event, context, callback)
}
テストを実行する
ここまで準備できれば、あとはテストコードをinvokeするだけです。
// Invoke the function by local
$ sls invoke local -f testAlexa
// Invoke AWS Lambda
$ sls invoke -f testAlexa
テスト結果はJSONで取得できます。
// Pass the test
{
"suite": {
"type": "suite",
"isPassing": true,
"numPassing": 2,
"numFailing": 0
},
"tests": [
{
"type": "test",
"durationInMillis": 0,
"testTitle": "test run",
"stackTrace": "",
"isPassing": true
},
{
"type": "test",
"durationInMillis": 4,
"testTitle": "test test11",
"stackTrace": "",
"isPassing": true
}
]
}
// Fail the test
{
"suite": {
"type": "suite",
"isPassing": false,
"numPassing": 0,
"numFailing": 1
},
"tests": [
{
"type": "test",
"durationInMillis": 5,
"testTitle": "test test11",
"stackTrace": "AssertionError [ERR_ASSERTION]: '<speak>hello</speak>' == '<speak>goodbye</speak>'\n at Decorator._callFunc (node_modules/empower-core/lib/decorator.js:110:20)\n at Decorator.concreteAssert (node_modules/empower-core/lib/decorator.js:103:17)\n at Function.decoratedAssert [as equal] (node_modules/empower-core/lib/decorate.js:51:30)\n at Context.it (tests/index.js:63:12)",
"isPassing": false
}
]
}