Choice (Word/String Alternatives)¶
Assume you need a user-defined data type with the following features:
- Only a limited number of words (or strings) should be matched
- All values are pre-defined (before the test)
Then the Choice type is a solution for your problem. Common use cases for the choice type are:
- text-based enumerations (string enum)
- color names
- …
Feature Example¶
Assuming you want to write something like this:
# file:datatype.features/choice.feature
Feature: User-Defined Choice Type
| The user-defined choice type supports only the following
| choice of words: apples, beef, potatoes, pork
Scenario: Good Case
Given I go to a shop to buy ingredients for a meal
When I buy apples
And I buy beef
Define the Data Type¶
# file:datatype.features/steps/step_choice.py
# ------------------------------------------------------------------------
# USER-DEFINED TYPES:
# ------------------------------------------------------------------------
from behave import register_type
from parse_type import TypeBuilder
# -- CHOICE: Constrain to a list of supported items (as string).
offered_shop_items = [ "apples", "beef", "potatoes", "pork" ]
parse_shop_item = TypeBuilder.make_choice(offered_shop_items)
register_type(ShopItem=parse_shop_item)
Note
The TypeBuilder.make_choice()
function performs the magic.
It computes a regular expression pattern for the given choice of
words/strings and stores them in parse_shop_item.pattern
attribute.
This optional attribute is used by the parse
module to improve
pattern matching for user-defined types.
Provide the Step Definitions¶
# file:datatype.features/steps/step_choice.py
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
from behave import given, when, then
@given(u"I go to a shop to buy ingredients for a meal")
def step_given_I_go_to_a_shop(context):
context.shopping_cart = [ ]
@when(u"I buy {shop_item:ShopItem}")
def step_when_I_buy(context, shop_item):
assert shop_item in offered_shop_items
context.shopping_cart.append(shop_item)
Run the Test¶
Now we run this example with behave
(and all steps are matched):
$ behave --tags=-xfail --no-skipped ../datatype.features/choice.feature Feature: User-Defined Choice Type # ../datatype.features/choice.feature:1 | The user-defined choice type supports only the following | choice of words: apples, beef, potatoes, pork Scenario: Good Case # ../datatype.features/choice.feature:6 Given I go to a shop to buy ingredients for a meal # ../datatype.features/steps/step_choice.py:34 When I buy apples # ../datatype.features/steps/step_choice.py:38 And I buy beef # ../datatype.features/steps/step_choice.py:38 1 feature passed, 0 failed, 0 skipped 1 scenario passed, 0 failed, 1 skipped 3 steps passed, 0 failed, 4 skipped, 0 undefined Took 0m0.001s
SAD Feature Example¶
The following feature example shows that only supported choice values are matched.
# file:datatype.features/choice.feature
Feature: User-Defined Choice Type
Scenario: Bad Case -- Undefined step definition for "diamonds"
Given I go to a shop to buy ingredients for a meal
When I buy apples
And I buy pork
And I buy diamonds
When you run this example with behave
the last step is not matched:
$ behave --tags=xfail --no-skipped ../datatype.features/choice.feature Feature: User-Defined Choice Type # ../datatype.features/choice.feature:1 | The user-defined choice type supports only the following | choice of words: apples, beef, potatoes, pork @xfail Scenario: Bad Case -- Undefined step definition for "diamonds" # ../datatype.features/choice.feature:12 Given I go to a shop to buy ingredients for a meal # ../datatype.features/steps/step_choice.py:34 When I buy apples # ../datatype.features/steps/step_choice.py:38 And I buy pork # ../datatype.features/steps/step_choice.py:38 And I buy diamonds # None You can implement step definitions for undefined steps with these snippets: @when(u'I buy diamonds') def step_impl(context): raise NotImplementedError(u'STEP: When I buy diamonds') Failing scenarios: ../datatype.features/choice.feature:12 Bad Case -- Undefined step definition for "diamonds" 0 features passed, 1 failed, 0 skipped 0 scenarios passed, 1 failed, 1 skipped 3 steps passed, 0 failed, 3 skipped, 1 undefined Took 0m0.001s
The Complete Picture¶
# file:datatypes.features/choice.feature
Feature: User-Defined Choice Type
| The user-defined choice type supports only the following
| choice of words: apples, beef, potatoes, pork
Scenario: Good Case
Given I go to a shop to buy ingredients for a meal
When I buy apples
And I buy beef
@xfail
Scenario: Bad Case -- Undefined step definition for "diamonds"
Given I go to a shop to buy ingredients for a meal
When I buy apples
And I buy pork
And I buy diamonds
# file:datatype.features/steps/step_choice.py
# -*- coding: UTF-8 -*-
"""
Based on ``behave tutorial``
Feature: User-Defined Choice Type (advanced tutorial01: choice)
| The user-defined choice type supports only the following words:
| apples, beef, potatoes, pork
Scenario:
Given I go to a shop to buy ingredients for a meal
And I buy apples
And I buy beef
"""
# @mark.user_defined_types
# ------------------------------------------------------------------------
# USER-DEFINED TYPES:
# ------------------------------------------------------------------------
from behave import register_type
from parse_type import TypeBuilder
# -- CHOICE: Constrain to a list of supported items (as string).
offered_shop_items = [ "apples", "beef", "potatoes", "pork" ]
parse_shop_item = TypeBuilder.make_choice(offered_shop_items)
register_type(ShopItem=parse_shop_item)
# @mark.steps
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
from behave import given, when, then
@given(u"I go to a shop to buy ingredients for a meal")
def step_given_I_go_to_a_shop(context):
context.shopping_cart = [ ]
@when(u"I buy {shop_item:ShopItem}")
def step_when_I_buy(context, shop_item):
assert shop_item in offered_shop_items
context.shopping_cart.append(shop_item)