Presentations
ptisnovs@redhat.com
https://github.com/tisnik/presentations/tree/master/Pyvo/BDD
https://github.com/tisnik/python-behave-demos
Given the customer has logged into their current account
And the balance is shown to be 100 euros
When the customer transfers 75 euros to their savings account
Then the new current account balance should be 25 euros
Test scenario parts:
Feature: Sum function test 1
Scenario: Check the function sum()
Given a list of integers
|value |
| 1 |
| 10 |
| 100 |
| 1000 |
When I summarize all those integers
Then I should get 1111 as a result
Feature: Interface to bank backend
Scenario: Check the exchange rate calculation
Given the following exchange rate table
| currency | rate |
| CZK | 1.000 |
| CAD | 16.172 |
| HRK | 3.407 |
| USD | 20.655 |
When I sell 10 CAD
Then I should receive 161.72 CZK
Scenario Outline: Check the user search feature, perform the search for more users
Given GitHub is accessible
When I search for user with nick <nick>
Then I should receive 200 status code
And I should receive proper JSON response
And I should find the user with full name <fullname>
And I should find that the user works for company <company>
Examples: users
|nick|fullname|company|
|torvalds|Linus Torvalds|Linux Foundation|
|brammool|Bram Moolenaar|Zimbu Labs|
|tisnik|Pavel Tišnovský|Red Hat, Inc.|
Scenario Outline: Check the exchange rate calculation
Given the following exchange rate table
| currency | rate |
| CZK | 1.000 |
| CAD | 16.172 |
| HRK | 3.407 |
| USD | 20.655 |
When I sell <sold> <currency>
Then I should receive <amount> CZK
Examples: sold
| sold | currency | amount |
| 1 | CZK | 1.000 |
| 10 | CZK | 10.000 |
| 1 | CAD | 16.172 |
| 100 | CAD | 1617.200 |
| 2 | HRK | 6.814 |
git clone https://github.com/tisnik/python-behave-demos
@capture
def before_all(context):
"""Perform setup before the first event."""
@capture
def before_scenario(context, scenario):
"""Perform setup before each scenario is run."""
@capture
def after_scenario(context, scenario):
"""Perform cleanup after each scenario is run."""
@capture
def after_all(context):
"""Perform cleanup after the last event."""
├── feature_list.txt
├── features
│ ├── adder.feature
│ └── steps
│ └── common.py
├── requirements.in
├── requirements.txt
├── run_tests.sh
└── src
└── adder.py
src/adder.py tested module
requirements.in/requirements.txt used by PIP
feature_list.txt list of test scenarios
features/ test scenario(s) + implementation of test steps
run_tests.sh helper script to run Behave
@smoketest
Scenario: Check the GitHub API entry point
Given GitHub is accessible
When I access the API endpoint /
Then I should receive 200 status code
Scenario: Check the user search feature
Given GitHub is accessible
When I search for user with nick torvalds
Then I should receive 200 status code
And I should receive proper JSON response
And I should find the user with full name Linus Torvalds
And I should find that the user works for company Linux Foundation
import json
import os.path
from behave.log_capture import capture
import requests
def _is_accessible(context, accepted_codes=None):
accepted_codes = accepted_codes or {200, 401}
url = context.api_url
try:
res = requests.get(url)
return res.status_code in accepted_codes
except requests.exceptions.ConnectionError as e:
print("Connection error: {e}".format(e=e))
return False
def before_all(context):
"""Perform setup before the first event."""
context.is_accessible = _is_accessible
context.api_url = "https://api.github.com"
@capture
def before_scenario(context, scenario):
"""Perform setup before each scenario is run."""
pass
@capture
def after_scenario(context, scenario):
"""Perform cleanup after each scenario is run."""
pass
@capture
def after_all(context):
"""Perform cleanup after the last event."""
pass
import json
from behave import given, then, when
from urllib.parse import urljoin
import requests
@given('GitHub is accessible')
def initial_state(context):
assert context.is_accessible(context)
@given('System is running')
def running_system(context):
"""Ensure that the system is accessible."""
assert is_accessible(context)
@when('I access the API endpoint {url}')
def access_endpoint(context, url):
context.response = requests.get(context.api_url + url)
@when('I search for user with nick {nick}')
def search_for_user(context, nick):
url = urljoin(urljoin(context.api_url, "users/"), nick)
context.response = requests.get(url)
@then('I should receive {status:d} status code')
def check_status_code(context, status):
"""Check the HTTP status code returned by the REST API."""
assert context.response.status_code == status
@then('I should receive proper JSON response')
def check_json_response(context):
content_type = context.response.headers.get('content-type')
assert content_type.startswith('application/json')
context.data = context.response.json()
@then('I should find the user with full name {fullname}')
def check_user_full_name(context, fullname):
assert context.data is not None
assert 'name' in context.data
value = context.data.get('name')
assert value == fullname, "{e} != {v}".format(e=fullname, v=value)
@then('I should find that the user works for company {company}')
def check_company(context, company):
assert context.data is not None
assert 'company' in context.data
value = context.data.get('company')
assert value == company, "{e} != {v}".format(e=company, v=value)