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

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark