Mycroft AI
  • Documentation
  • About Mycroft AI
    • Why use Mycroft AI?
    • Glossary of terms
    • Contributing
    • FAQ
  • Using Mycroft AI
    • Get Mycroft
      • Mark II
        • Mark II Dev Kit
      • Mark 1
      • Picroft
      • Linux
      • Mac OS and Windows with VirtualBox
      • Docker
      • Android
    • Pairing Your Device
    • Basic Commands
    • Installing New Skills
    • Customizations
      • Configuration Manager
      • mycroft.conf
      • Languages
        • Français (French)
        • Deutsch (German)
      • Using a Custom Wake Word
      • Speech-To-Text
      • Text-To-Speech
    • Troubleshooting
      • General Troubleshooting
      • Audio Troubleshooting
      • Wake Word Troubleshooting
      • Log Files
      • Support Skill
      • Getting more support
  • Skill Development
    • Voice User Interface Design Guidelines
      • What can a Skill do?
      • Design Process
      • Voice Assistant Personas
      • Interactions
        • Intents
        • Statements and Prompts
        • Confirmations
      • Conversations
      • Error Handling
      • Example Interaction Script
      • Prototyping
      • Design to Development
    • Development Setup
      • Python Resources
      • Your First Skill
    • Skill Structure
      • Lifecycle Methods
      • Logging
      • Skill Settings
      • Dependencies
        • Manifest.yml
        • Requirements files
      • Filesystem access
      • Skill API
    • Integration Tests
      • Test Steps
      • Scenario Outlines
      • Test Runner
      • Reviewing the Report
      • Adding Custom Steps
      • Old Test System
    • User interaction
      • Intents
        • Padatious Intents
        • Adapt Intents
      • Statements
      • Prompts
      • Parsing Utterances
      • Confirmations
      • Conversational Context
      • Converse
    • Displaying information
      • GUI Framework
      • Show Simple Content
      • Mycroft-GUI on a PC
      • Mark 1 Display
    • Advanced Skill Types
      • Fallback Skill
      • Common Play Framework
      • Common Query Framework
      • Common IoT Framework
    • Mycroft Skills Manager
      • Troubleshooting
    • Marketplace Submission
      • Skills Acceptance Process
        • Information Review Template
        • Code Review Template
        • Functional Review Template
        • Combined Template
      • Skill README.md
    • FAQ
  • Mycroft Technologies
    • Technology Overview
    • Roadmap
    • Mycroft Core
      • MessageBus
      • Message Types
      • Services
        • Enclosure
        • Voice Service
        • Audio Service
        • Skills Service
      • Plugins
        • Audioservice Plugins
        • STT Plugins
        • TTS Plugins
        • Wake Word Plugins
      • Testing
      • Legacy Repo
    • Adapt
      • Adapt Examples
      • Adapt Tutorial
    • Lingua Franca
    • Mimic TTS
      • Mimic 3
      • Mimic 2
      • Mimic 1
      • Mimic Recording Studio
    • Mycroft GUI
      • Remote STT and TTS
    • Mycroft Skills Kit
    • Mycroft Skills Manager
    • Padatious
    • Precise
    • Platforms
Powered by GitBook
On this page
  • Packages
  • Voight Kampff Tools
  • Decorators
  • Function arguments
  • Context Object
  • Step logic
  • Help

Was this helpful?

  1. Skill Development
  2. Integration Tests

Adding Custom Steps

Some Skills require their own unique Steps to test functionality specific to that Skill.

PreviousReviewing the ReportNextOld Test System

Last updated 5 years ago

Was this helpful?

Custom Steps can be added to your Skills repository within the test/behave/steps directory.

The Mycroft Timer Skill for example provides . This has a range of custom Steps to ensure the system is in an appropriate state before the test is run, and that a timer is stopped correctly when requested.

Let's use an example from this Skill to see how we can define our own custom Steps.

from behave import given

from test.integrationtests.voight_kampff import wait_for_dialog, emit_utterance


@given('a {timer_length} timer is set')
@given('a timer is set for {timer_length}')
def given_set_timer_length(context, timer_length):
    emit_utterance(context.bus, 'set a timer for {}'.format(timer_length))
    wait_for_dialog(context.bus, ['started.timer'])
    context.log.info('Created timer for {}'.format(timer_length))
    context.bus.clear_messages()

Packages

First we import some packages.

from behave import given

from test.integrationtests.voight_kampff import wait_for_dialog, emit_utterance

From behave we can get the behave decorators - given, when, or then. For this Step we also need some helper functions from the Voight Kampff module.

Like any Python script, you can import other packages from Mycroft or externally as needed.

Voight Kampff Tools

The test.integrationtests.voight_kampff module provides a number of common tools that may be useful when creating Step files.

then_wait(msg_type, criteria_func, context, timeout=10)

Wait for a specified time for criteria to be fulfilled.

Arguments:

msg_type - Message type to watch criteria_func - Function to determine if a message fulfilling the test case has been found. context - Behave context object timeout - Time allowance for a message fulfilling the criteria, defaults to 10 sec

Returns:

tuple (bool, str) - test status, debug output

mycroft_responses(context)

Collect and format mycroft responses from context.

Arguments:

context - Behave context to extract messages from.

Returns:

(str) - Mycroft responses including skill and dialog file

emit_utterance(bus, utt)

Emit an utterance on the bus.

Arguments:

bus (InterceptAllBusClient) - Bus instance to listen on dialogs (list) - List of acceptable dialogs

Returns:

None

wait_for_dialog(bus, dialogs, timeout=10)

Wait for one of the dialogs given as argument.

Arguments:

bus (InterceptAllBusClient) - Bus instance to listen on dialogs (list) - list of acceptable dialogs timeout (int) - Time allowance to wait, defaults to 10 sec

Returns:

None

Decorators

Now we can use the @given() decorator on our function definition.

@given('a {timer_length} timer is set')
@given('a timer is set for {timer_length}')
def given_set_timer_length(context, timer_length):

This decorator tells the system that we are creating a Given Step. It takes a string as it's first argument which defines what phrase we can use in our tests. So using the first decorator above means that in our tests we can then write Given Steps like:

Given a 10 minute timer is set

A handy feature of decorators is that they can be stacked. In this example we have two stacked decorators applied to the same function. This allows us to use variations of natural language, and both versions will achieve the same result. So now we could write another Step phrased differently:

Given a timer is set for 10 minutes

Either way, it will ensure a 10 minute timer exists before running the test Scenario.

Function arguments

@given('a {timer_length} timer is set')
@given('a timer is set for {timer_length}')
def given_set_timer_length(context, timer_length):

In our current example, we have only one variable "timer_length". This corresponds to the second argument of our function. Additional variables can be added to the argument list such as:

@given('a timer named {timer_name} is set for {timer_length}')
def given_set_timer_named(context, timer_name, timer_length):

Context Object

context.bus - an instance of the Mycroft MessageBusClient class. context.log - an instance of the Python standard library logging.Logger class. context.msm - a reference to the Mycroft Skills Manager

Step logic

Now we have the structure of our Step function in place, it's time to look at what that Step does.

def given_set_timer_length(context, timer_length):
    emit_utterance(context.bus, 'set a timer for {}'.format(timer_length))
    wait_for_dialog(context.bus, ['started.timer'])
    context.log.info('Created timer for {}'.format(timer_length))
    context.bus.clear_messages()

In this example we have four lines:

  1. Emitting an utterance to the Mycroft MessageBus to create a timer for the given length of time.

  2. Waiting for dialog to be returned from the MessageBus confirming that the timer has been started.

  3. Logging an info level message to confirm we created a timer.

  4. Clearing any remaining messages from the MessageBus to prevent interference with the test.

Note: the log message in this Step isn't really necessary. Voight Kampff will confirm that each Step is completed successfully. It just serves as a useful example to show how messages can be logged.

Help

When we define a Step function, the first argument will always be a . All remaining arguments will map to variables defined in the decorators.

The first argument of each Step function is always a , with some additional properties added by Voight Kampff. These are:

For further assistance with Skill testing, please post your question on the or in the .

See our . This helps you get a more complete response faster.

test/behave/steps/timer.py
Behave Context Object
Behave Context Object
Community Forums
Skills channel on Mycroft Chat
tips for how to ask the best questions