Tutorial 7: Result Table¶
Goal: | Use result tables to simplify comparison of an expected dataset. |
---|
The usage of result tables come in variations. It often depends what you want to compare. These variations in the test automation layer are:
- ordered dataset comparison
- unordered dataset comparison
- ordered subset comparison (result table contains subset)
- unordered subset comparison (result table contains subset)
Hint
The FIT test framework provides similar concepts via Fixtures. An extension of FIT, the FitLibrary, provides even more advanced fixtures classes/tables.
Dataset | Unordered comparison | Ordered Comparison |
---|---|---|
Subset | fitlibrary.SubsetFixture, fit.RowFixture (with table args) | fitlibrary.ArrayFixture (variant) |
Complete | fit.RowFixture, fitlibrary.SetFixture | fitlibrary.ArrayFixture |
Besides other descriptions of these Fixtures, the Fixture Gallery project provides examples for these fixture in several languages.
Both, unordered dataset comparison and unordered subset comparison are used in this tutorial in two different scenarios.
Write the Feature Test¶
# file:features/tutorial07_step_result_table.feature
Feature: Step Result Table (tutorial07)
Scenario: Unordered Result Table Comparison (RowFixture Table)
Given a set of specific users:
| name | department |
| Alice | Beer Cans |
| Bob | Beer Cans |
| Charly | Silly Walks |
| Dodo | Silly Walks |
Then we will have the following people in "Silly Walks":
| name |
| Charly |
| Dodo |
And we will have the following people in "Beer Cans":
| name |
| Bob |
| Alice |
Scenario: Subset Result Table Comparison
Given a set of specific users:
| name | department |
| Alice | Super-sonic Cars |
| Bob | Super-sonic Cars |
Then we will have at least the following people in "Super-sonic Cars":
| name |
| Alice |
Provide the Test Automation¶
# file:features/steps/step_tutorial07.py
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
from behave import given, when, then
from hamcrest import assert_that, has_items
from hamcrest.library.collection.issequence_containinginanyorder \
import contains_inanyorder
@then('we will have the following people in "{department}"')
def step_impl(context, department):
"""
Compares expected with actual persons in a department.
NOTE: Unordered comparison (ordering is not important).
"""
department_ = context.model.departments.get(department, None)
if not department_:
assert_that(False, "Department %s is unknown" % department)
# -- NORMAl-CASE:
expected_persons = [ row["name"] for row in context.table ]
actual_persons = department_.members
# -- UNORDERED TABLE-COMPARISON (using: pyhamcrest)
assert_that(contains_inanyorder(*expected_persons), actual_persons)
@then('we will have at least the following people in "{department}"')
def step_impl(context, department):
"""
Compares subset of persons with actual persons in a department.
NOTE: Unordered subset comparison.
"""
department_ = context.model.departments.get(department, None)
if not department_:
assert_that(False, "Department %s is unknown" % department)
# -- NORMAl-CASE:
expected_persons = [ row["name"] for row in context.table ]
actual_persons = department_.members
# -- TABLE-SUBSET-COMPARISON (using: pyhamcrest)
assert_that(has_items(*expected_persons), actual_persons)
# @mark.more_steps
# ----------------------------------------------------------------------------
# MORE STEPS: step_tutorial06.py
# ----------------------------------------------------------------------------
# @given('a set of specific users')
# def step_impl(context):
# model = getattr(context, "model", None)
# if not model:
# context.model = CompanyModel()
# for row in context.table:
# context.model.add_user(row["name"], deparment=row["department"])
#
# @when('we count the number of people in each department')
# def step_impl(context):
# context.model.count_persons_per_department()
Provide the Domain Model¶
# file:features/steps/company_model.py
# -----------------------------------------------------------------------------
# DOMAIN-MODEL:
# -----------------------------------------------------------------------------
class Department(object):
def __init__(self, name, members=None):
if not members:
members = []
self.name = name
self.members = members
def add_member(self, name):
assert name not in self.members
self.members.append(name)
@property
def count(self):
return len(self.members)
def __len__(self):
return self.count
class CompanyModel(object):
def __init__(self):
self.users = []
self.departments = {}
def add_user(self, name, deparment):
assert name not in self.users
if deparment not in self.departments:
self.departments[deparment] = Department(deparment)
self.departments[deparment].add_member(name)
def count_persons_per_department(self):
pass
def get_headcount_for(self, department):
return self.departments[department].count
Run the Feature Test¶
When you run the feature file from above:
$ behave ../features/tutorial07_step_result_table.feature Feature: Step Result Table (tutorial07) # ../features/tutorial07_step_result_table.feature:1 Scenario: Unordered Result Table Comparison (RowFixture Table) # ../features/tutorial07_step_result_table.feature:3 Given a set of specific users # ../features/steps/step_tutorial06.py:28 | name | department | | Alice | Beer Cans | | Bob | Beer Cans | | Charly | Silly Walks | | Dodo | Silly Walks | Then we will have the following people in "Silly Walks" # ../features/steps/step_tutorial07.py:46 | name | | Charly | | Dodo | And we will have the following people in "Beer Cans" # ../features/steps/step_tutorial07.py:46 | name | | Bob | | Alice | Scenario: Subset Result Table Comparison # ../features/tutorial07_step_result_table.feature:20 Given a set of specific users # ../features/steps/step_tutorial06.py:28 | name | department | | Alice | Super-sonic Cars | | Bob | Super-sonic Cars | Then we will have at least the following people in "Super-sonic Cars" # ../features/steps/step_tutorial07.py:62 | name | | Alice | 1 feature passed, 0 failed, 0 skipped 2 scenarios passed, 0 failed, 0 skipped 5 steps passed, 0 failed, 0 skipped, 0 undefined Took 0m0.002s