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
        }
      ]
    }

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

    Random posts

    Home
    Search
    Bookmark