Amazon AlexaAWS

Jestのモックを使ってインテント別にalexa-sdkで実装したコードをテストする

この記事は一人Alexa Skills Kit for Node.js Advent Calendar 2017の12日目の記事です。 alexa-sdkでコードを書く場合、以下のようなコードになります。 const A […]

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

この記事は一人Alexa Skills Kit for Node.js Advent Calendar 2017の12日目の記事です。

alexa-sdkでコードを書く場合、以下のようなコードになります。

const Alexa = require('alexa-sdk')
const handlers = {
  LaunchRequest: function () {
    alexa.emit(':tell', 'Hello World!')
  }
}

module.exports.handler = function (event, context, callback) {
  const alexa = Alexa.handler(event, context)
  alexa.registerHandlers(handlers)
  alexa.execute()
}

これまで紹介したテストは、基本的にAWS Lambdaがコールするmodule.exports.handlerでテストをしていました。

今回はもうすこしスコープを小さく絞って以下の部分をテストしてみたいと思います。

LaunchRequest: function () {
    alexa.emit(':tell', 'Hello World!')
  }

テストできるように分割する

ぱっと見たところ問題点は2つあります。

  • exportsされていないのでLaunchRequest()をテストファイルからよべない
  • this.emitのようにthisに依存している関数がある

ということでまずはこの2つを解消しましょう。

handlerを別ファイルに切り出す

とりあえずファイルを分割しましょう。

変更後のhandlers.js

module.exports = {
  LaunchRequest: function () {
    alexa.emit(':tell', 'Hello World!')
  }
}

これで以下の例のようにLaunchRequest単体をよびだせるようになりました。

const handlers = require('handlers')
handlers.LaunchRequest()

変更後のindex.js

元ファイルの方も切り出したものをつかうように変更します。

const Alexa = require('alexa-sdk')
const handlers = require('handlers')

module.exports.handler = function (event, context, callback) {
  const alexa = Alexa.handler(event, context)
  alexa.registerHandlers(handlers)
  alexa.execute()
}

ここでこれまで紹介したようなテストをまわしておくと、ちゃんと動くか確認できます。

「接合部」を作ってテスト可能なコードにする

このままではhandlers.LaunchRequest()を実行しても、this.emitがないというエラーが出るだけです。

ということでt_wadaさんのセッションを参考に「接合部」を作るようにします。

https://speakerdeck.com/twada/testable-lambda-working-effectively-with-legacy-lambda?slide=37
参考:Testable Lambda: Working Effectively with Legacy Lambda P.37

変更後のhandlers.js

LaunchRequestの中で実行するのではなく、makeResponse関数にthisを渡してそちらで実行するようにしました。
同時にmakeResponseについてもテストファイルからよめるようにexportしておきます。

const handlers = {
  LaunchRequest: function () {
    makeResponse(this)
  }
}

function makeResponse (alexa) {
  alexa.emit(':tell', 'Hello World!')
}

exports.handlers = handlers
exports.makeResponse = makeResponse

変更後のindex.js

exportの仕方が変わったため、こちらも変更しておきます。

const Alexa = require('alexa-sdk')
const libs = require('handlers')

module.exports.handler = function (event, context, callback) {
  const alexa = Alexa.handler(event, context)
  alexa.registerHandlers(libs.handlers)
  alexa.execute()
}

これで準備ができました。

Jestでテストを書く

ここからはJestでテストを書いていきます。

LaunchRequest.test.js

ということで作成したものがこちらです。

/* global describe, it, jest, expect */
const handlers = require('./handlers')

describe('LaunchRequest', () => {
  // emit()のモックを作成する
  const mockAlexa = {
    emit: jest.fn()
  }
  it('makeResponse()', () => {
    handlers.makeResponse(mockAlexa)

    // emit()が1度だけコールされていることをテストする
    expect(mockAlexa.emit.mock.calls.length).toBe(1)

    // emit()の引数が正しいものかをテストする
    expect(mockAlexa.emit.mock.calls[0][0]).toBe(':tell')
    expect(mockAlexa.emit.mock.calls[0][1]).toBe('Hello World!')
  })
})

テストを実行する

あとはテストを実行するだけです。

$ ./node_modules/jest/bin/jest.js 
 PASS  __tests__/LaunchRequest.test.js

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.504s
Ran all test suites.

おわりに

今回紹介した例では1行だけしかない関数のテストでしたが、外部のAPIと接続したり複雑な処理を走らせたい場合などに便利かなと思います。

Lambdaのhandlerを通してのテストの場合、eventの値をフルで渡す必要があったりcontext.succeedcontext.failのそれぞれにアサーションを書かないとだったりなので、手早くテストしたい場合にもおすすめです。

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

WP Kyotoサポーター募集中

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

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

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

Related Category posts