はじめに
Alexaスキル開発では、S3にデータを保存することがよくあります。
S3を使うためには、AWSのCredentialが必要になるのですが、わざわざテストのために管理するのはめんどくさいです。
LocalStack と ask-sdk-test を使って、いい感じにテストが出来る方法をやってみました。
やってみた
TypeScript, Serverless Frameworkを利用していますが、細かい部分は省略しています。
JavaScriptを利用する場合は、適宜読み替えていただければと思います。
LocalStack
LocalStackを使ってS3をローカルで動かします。
docker-composeを利用します。
docker-compose.yml
version: '2.1'
services:
localstack:
container_name: "localstack_main"
image: localstack/localstack
ports:
- "4566:4566"
environment:
- SERVICES=s3
ダミーのProfileを設定します。
~/.aws/config
[default]
output = json
region = ap-northeast-1
[profile localstack]
output = json
region = ap-northeast-1
~/.aws/credentials
[default]
aws_access_key_id = dummy
aws_secret_access_key = dummy
[localstack]
aws_access_key_id = dummy
aws_secret_access_key = dummy
LocalStackを起動して、Alexaで使うS3のデータを作っておきます。
$ docker-compose up -d
$ aws --endpoint-url http://localhost:4566 --profile localstack s3 mb s3://sample-skill-test
$ echo '{"hello": "world"}' | aws --endpoint-url http://localhost:4566 --profile localstack s3 cp - s3://sample-skill-test/amzn1.ask.account.VOID
Alexaスキル
一部の抜粋になりますが、ask-sdk-testが動くようにします。
(もしかしたら他にも必要なパッケージがあるかも... )
package.json
{
...
"scripts": {
"test": "npx mocha -r ts-node/register -r tsconfig-paths/register test/index.spec.ts",
},
"devDependencies": {
"@types/mocha": "8.0.3",
"ask-sdk-test": "^2.5.0",
"mocha": "8.2.1",
...
},
...
}
ハローワールドのスキルを修正して、S3からデータを引っ張ってきます。
handler.ts
import AWS from "aws-sdk";
// s3ForcePathStyle を設定しないとhostの解決で失敗する
AWS.config.update({ region: "ap-northeast-1", s3ForcePathStyle: true });
// s3の設定
// testの時はLocalStackを使う
const s3PersistenceAdapter = new Adapter.S3PersistenceAdapter({
bucketName: "sample-skill-test",
s3Client: process.env.ENV == "test" ?
new AWS.S3({endpoint: "http://localhost:4566"}) :
new AWS.S3()
});
// handler
const LaunchRequestHandler = {
canHandle(handlerInput: Ask.HandlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === "LaunchRequest";
},
async handle(handlerInput: Ask.HandlerInput) {
const { hello } = await handlerInput.attributesManager.getPersistentAttributes();
return handlerInput.responseBuilder
.speak(hello)
.withShouldEndSession(true)
.getResponse();
}
};
// Alexaの設定
export const alexa = Ask.SkillBuilders.custom()
.addRequestHandlers(LaunchRequestHandler)
.withApiClient(new Ask.DefaultApiClient())
.withPersistenceAdapter(s3PersistenceAdapter)
.lambda();
world
というS3のデータが帰ってくるかを確認するテストです。
test/index.spec.ts
import { describe } from "mocha";
import {
AlexaTest,
LaunchRequestBuilder,
SkillSettings
} from "ask-sdk-test";
process.env.ENV = "test";
import { alexa as skillHandler } from "../handler.ts";
// initialize the testing framework
const skillSettings: SkillSettings = {
appId: "amzn1.ask.skill.00000000-0000-0000-0000-000000000000",
userId: "amzn1.ask.account.VOID",
deviceId: "amzn1.ask.device.VOID",
locale: "en-US"
};
const alexaTest = new AlexaTest(skillHandler, skillSettings);
describe("LaunchRequest", () => {
alexaTest.test([
{
request: new LaunchRequestBuilder(skillSettings).build(),
says: "world",
repromptsNothing: true,
shouldEndSession: true
}
]);
});
テストを実行します。
$ npm run test
> npx mocha -r ts-node/register -r tsconfig-paths/register test/index.spec.ts
...
LaunchRequest
✓ returns the correct responses (52ms)
1 passing (60ms)
まとめ
- LocalStackを使って、Alexaスキルのテストをローカル環境で動かしました。
- Github Actionsに組み込んでCIを作れたり、AWS費用がかからないのもよいです。
- LocalStackは、S3だけでなくDynamoDBなど他のAWSサービスにも対応しているので、いろいろ応用出来るかと思います。
参考