Test your Java Alexa skills
This tutorial will help you write automated test cases for Alexa skills written in Java. Using real-life JSON requests and verifying multi-turn interactions without deploying or hosting the skill.
To use the alexa-skills-tester, just add the following to your project:
(replace VERSION with the current release).
<dependency>
<groupId>info.tomfi.alexa</groupId>
<artifactId>alexa-skills-tester</artifactId>
<version>VERSION</version>
</dependency>
Example usage
Using a basic Nice to meet you
custom skill:
When launching the skill, it asks for the user name and then replies with a Nice to meet you #name
prompt, ending the session.
Let's take a look at the code for the skill.
A launch request handler
public final class LaunchRequestHandlerImpl implements LaunchRequestHandler {
@Override
public boolean canHandle(final HandlerInput input, final LaunchRequest request) {
return true;
}
@Override
public Optional<Response> handle(final HandlerInput input, final LaunchRequest request) {
return input.getResponseBuilder()
.withSpeech("What is your name?")
.withReprompt("Please tell me your name.")
.withShouldEndSession(false)
.build();
}
}
An intent request handler handling MyNameIntent
with a nameSlot
public final class MyNameIntentRequestHandler implements IntentRequestHandler {
@Override
public boolean canHandle(final HandlerInput input, final IntentRequest request) {
return request.getIntent().getName().equals("MyNameIntent");
}
@Override
public Optional<Response> handle(final HandlerInput input, final IntentRequest request) {
var name = request.getIntent().getSlots().get("nameSlot").getValue();
return input.getResponseBuilder()
.withSpeech(String.format("Nice to meet you %s!", name))
.withShouldEndSession(true)
.build();
}
}
A session ended request handler
public final class SessionEndedRequestHandlerImpl implements SessionEndedRequestHandler {
@Override
public boolean canHandle(final HandlerInput input, final SessionEndedRequest request) {
return true;
}
@Override
public Optional<Response> handle(final HandlerInput input, final SessionEndedRequest request) {
return Optional.empty();
}
}
A utility class for constructing the skill
class NiceToMeetYouSkill {
public static Skill getSkill() {
return Skills.standard()
.addRequestHandler(new LaunchRequestHandlerImpl())
.addRequestHandler(new MyNameIntentRequestHandler())
.addRequestHandler(new SessionEndedRequestHandlerImpl())
.build();
}
}
Now, let's test the skill
You should get familiarized with Alexa's Request and Response JSON Reference. This is, of course, should be considered common knowledge for skill developers.
Let's create a couple of fake request JSON files to use in our tests.
launch_request.json
{
"version": "1.0",
"session": {
"new": true
},
"context": {
"System": {}
},
"request": {
"type": "LaunchRequest",
"requestId": "amzn1.echo-api.request.fake-request-id",
"timestamp": "2021-02-11T15:30:00Z",
"locale": "en-US"
}
}
my_name_intent.json
{
"version": "1.0",
"session": {
"new": false
},
"context": {
"System": {}
},
"request": {
"type": "IntentRequest",
"requestId": "amzn1.echo-api.request.fake-request-id",
"timestamp": "2021-02-11T15:31:00Z",
"locale": "en-US",
"intent": {
"name": "MyNameIntent",
"slots": {
"nameSlot": {
"name": "nameSlot",
"value": "master"
}
}
}
}
}
session_ended.json
{
"version": "1.0",
"session": {
"new": false
},
"context": {
"System": {}
},
"request": {
"type": "SessionEndedRequest",
"requestId": "amzn1.echo-api.request.fake-request-id",
"timestamp": "2021-02-11T15:32:00Z",
"locale": "en-US"
}
}
Now, let's create some test cases leveraging the above JSON files to verify the interaction with the skill.
Test cases testing the Nice to meet you
skill
final class SkillInteractionTest {
@Test
void verify_greeting_for_my_name_intent_as_a_followup_to_a_launch_request() throws IOException {
givenSkill(NiceToMeetYouSkill.getSkill())
.whenRequestIs(getClass().getClassLoader().getResourceAsStream("launch_request.json").readAllBytes())
.thenResponseShould()
.waitForFollowup()
.haveOutputSpeechOf("What is your name?")
.haveRepromptSpeechOf("Please tell me your name.")
.followingUpWith(getClass().getClassLoader().getResourceAsStream("my_name_intent.json").readAllBytes())
.thenResponseShould()
.haveOutputSpeechOf("Nice to meet you master!")
.and()
.notWaitForFollowup();
}
@Test
void verify_empty_response_for_session_ended_requests() throws IOException {
givenSkill(NiceToMeetYouSkill.getSkill())
.whenRequestIs(getClass().getClassLoader().getResourceAsStream("launch_request.json").readAllBytes())
.thenResponseShould()
.waitForFollowup()
.haveOutputSpeechOf("What is your name?")
.haveRepromptSpeechOf("Please tell me your name.")
.followingUpWith(getClass().getClassLoader().getResourceAsStream("session_ended.json").readAllBytes())
.thenResponseShould().beEmpty();
}
}
That's it!
I hope you'll find this tool useful.
Top comments (1)
Great post @tomerfi :)
I will give a try in my skills!
Thanks