Amazon Alexaask-sdk

Execute mocha unit test for your Alexa custom skill in an AWS Lambda

VUI application like a Alexa skill should monitor the application health. So some developer like me want to ru […]

広告ここから
広告ここまで

VUI application like a Alexa skill should monitor the application health.

So some developer like me want to run testing code in production.

In AWS, we can run Mocha unittest by using AWS Lambda.

Target function

This is the simple skill code.

$ 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()

And we will be add test code

Preparation

Create a new project by Serverless Framework

We can easy to create and deploy AWS resources by the Serverless Framework.

$ sls create -t aws-nodejs-ecma-script -p lambda-alexa-monitor
$ cd lambda-alexa-monitor
$ npm i

Install npm libraries

And install lambda-mocha-runner package.

$ npm i -S lambda-mocha-runner ask-sdk mocha power-assert

The lambda-mocha-runner runs mocha test in AWS Lambda.

Make test files

Finally, we can make a test file by the specific directory.

$ mkdir tests
$ touch tests/index.js

Write test code

Next, we will create a new test code to the Lambda function.

$ vim tests/index.js
const assert = require('power-assert')

const {
  handler
} = require('../index')

// Alexa Skills Kit request object
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 wrapper to invoke the function
const invokeHandler = async (handler, event) => {
  return new Promise((resolve, reject) => {
    return handler(event, {}, (err, result) => {
      if (err) return reject(err)
      return resolve(result)
    })
  })
}

// execute test
describe('test', () => {
  it('test11', async () => {
    const r = await invokeHandler(handler, event)
    assert.equal(r.response.outputSpeech.ssml, '<speak>hello</speak>')
  })
})

Make a test function

Finally, we can make a new Lambda function to execute the test.

Define AWS Resource

Define AWS resources by the Serverless Framework.

$ 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 * * * ? *)

It will be created a new AWS Lambda and CloudWatch Event.

Write a execution tests

And make a js file to execute test.

$ 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)
}

Run the test

That’s complete! We can run test by the CloudWatch Schedule event or specific request.

// Invoke the function by local
$ sls invoke local -f testAlexa

// Invoke AWS Lambda
$ sls invoke -f testAlexa

And we can see the test result by the following 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
    }
  ]
}

ブックマークや限定記事(予定)など

WP Kyotoサポーター募集中

WordPressやフロントエンドアプリのホスティング、Algolia・AWSなどのサービス利用料を支援する「WP Kyotoサポーター」を募集しています。
月額または年額の有料プランを契約すると、ブックマーク機能などのサポーター限定機能がご利用いただけます。

14日間のトライアルも用意しておりますので、「このサイトよく見るな」という方はぜひご検討ください。

広告ここから
広告ここまで

Related Category posts