TypeScript を使って Alexa Custom Skills を作ろう 番外編 機能テスト

# はじめに

[TypeScript を使って Alexa Custom Skills を作ろう](https://qiita.com/daisukeArk/items/ac45f10d2fc8fe8bdc5a)では、設計〜実装、単体テストまでをご紹介しました。
本投稿では番外編として、`alexa-conversation`を利用した機能テストについてご紹介します。

`alexa-conversation`については[前回の投稿（単体テスト編）](https://qiita.com/daisukeArk/items/afa12708810a6b0b0fde)でご紹介したので、さっそく機能テスト方法についてご紹介します。

# 機能テストしようぜ

## まずは、ライブラリのインストールから（お決まり）

```bash:移動
$ cd ~/custom-skill-sample-to-convert/skill/lambda/custom
```

```bash:alexa-conversationのインストール
$ npm install --save-dev alexa-conversation
```

## テスト作成前の準備

```bash:テストディレクトリの作成
$ mkdir -p ./src/tests/conversations
```

```bash:テストファイルの作成
$ touch ./src/tests/conversations/default-handler.test.ts
```

```bash:alexa-conversationパラメータ用外部モジュールファイルの作成
$ touch ./src/tests/conversation-options.ts
```

`alexa-conversation`に渡すパラメータ設定を作成します。

```typescript:./src/tests/conversation-options.ts
import * as App from '../index';

/**
 * alexa-conversationパラメータ
 */
export const options = {
  name: 'タイろう　テスト',
  app: App,
  appId: 'amzn1.ask.skill.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  locale: 'ja-JP',
  fixSpaces: true
};
```

## テストを書く

今回のテストでは、ヘルプインテントが呼び出された際に返される発話内容が完全一致するかを評価します。

```typescript:./src/tests/conversations/default-handler.test.ts
import * as conversation from 'alexa-conversation';
import { options } from '../conversation-options';
import { languageStrings } from './../../utterances/language-strings';

/**
 * ヘルプインテントの機能テスト
 */
conversation(options)
  // ヘルプインテントの呼出
  .userSays('AMAZON.HelpIntent')
  // 応答をテキストで受け取る
  .plainResponse
  // 応答テキストと想定している発話内容が完全一致しているか判定
  .shouldEqual(languageStrings['ja-JP'].translation.ASK_HELP_MESSAGE)
  // 終了
  .end();
```

ここで１つ問題が発生します。
`alexa-conversation`はDTに型定義がありません。。。

なので、importで以下のエラーが発生します。

```text
[ts]
モジュール 'alexa-conversation' の宣言ファイルが見つかりませんでした。
'~/custom-skill-sample-to-convert/skill/lambda/custom/node_modules/alexa-conversation/index.js' は暗黙的に 'any' 型になります。
`npm install @types/alexa-conversation` を試すか (存在する場合)、
`declare module 'alexa-conversation';` を含む新しい宣言 (.d.ts) ファイルを追加してください
```

これを解決する為に、いくつか方法が提示されていますが今回は型定義を自前で用意する選択をしました。

## 型定義をつくろう

今回の型定義は完璧なものを目指したものではありません。
あくまでトランスパイルできるところまでを目標にしています。

### まずは、型定義を入れる場所を作ろう

```bash:テストディレクトリの作成
$ mkdir -p ./mytypes
```

```bash:型定義ファイルの作成
$ touch ./mytypes/alexa-conversation.d.ts
```

### `alexa-conversation`の型定義をする

```./mytypes/alexa-conversation.d.ts
declare namespace AlexaConversation {
  interface IConversation {
    (options: IOptions): IApi;
  }

  export interface IOptions {
    name: any,
    app: any,
    appId: any,
    sessionId?: any,
    userId?: any,
    accessToken?: any,
    requestId?: any,
    locale?: any,
    fixSpaces?: any,
    fuzzyDistance?: any,
    handler?: any
  }

  interface IApi {
    userSays(intentName: string, slotsArg?: any): IApi;
    plainResponse: any;
    ssmlResponse: any;
    end(): void;
  }
}

declare const conversation: AlexaConversation.IConversation;

declare module 'alexa-conversation' {
  export = conversation;
}
```

### 作成した型定義を読み込ませる

型定義を読み込ませる為に、`tsconfig.json`の以下の箇所を修正します。

```json:tsconfig.json
"baseUrl": ".",
"paths": {
  "alexa-conversation": [
    "./mytypes/alexa-conversation"
  ]
},     
```

## トランスパイルしてみましょう

```bash:トランスパイル（エラーが出なければ、成功！）
$ tsc
```

## では、テストを実行します

```bash:テスト実行
$ $(npm bin)/mocha ./dist/tests/conversations/default-handler.test.js
```

```bash:結果の確認
Warning: Application ID is not set
  Executing conversation: タイろう　テスト
    ✓ Finished executing conversation

  Conversation: タイろう　テスト
    User triggers: AMAZON.HelpIntent
      ✓ Alexa's plain text response should equal: 声を聞かせて、と言ってください。


  2 passing (30ms)
```

正常終了しました。
ヘルプインテントから返される発話内容が完全一致することを確認できました。

# まとめ

この投稿では、`alexa-conversation`の型定義を自作で作り、`default-handler`のヘルプインテント機能テストを行いました。
対話形式で書くことによって、実際に会話しているような感覚でテストが可能になります。

実機で確認する前の最終確認として利用することでLambdaへのデプロイ頻度が下がることが期待できると思います。

今回の投稿のソースは以下にあります。
[機能テスト](https://github.com/daisukeArk/custom-skill-sample-to-convert/tree/dev/functional-test)