-
Notifications
You must be signed in to change notification settings - Fork 89
Nested steps
Nested steps is a common way to group your test logs into small described pieces. Here is how one of our internal test looks like:
Let's imagine we have a test for some products ordering flow:
import logging
from web import OrderingSimulator
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
order_simulator = OrderingSimulator()
def test_order_products():
product_count = 5
price = 3.0
total_price = price * product_count
logger.info('Main page displayed')
order_simulator.log_in()
logger.info('User logged in')
products = order_simulator.get_products()
logger.info('Products page opened')
product = order_simulator.choose_product()
logger.info("Product click event")
logger.info(str(product_count) + " products selected")
order_simulator.add_product(product, product_count)
logger.info(str(product_count) + " products added to the cart")
assert 5 == product_count
order_simulator.do_payment(total_price)
logger.info("Successful payment")
order_simulator.log_out()
logger.info("User logged out")
After running this method with our listener we have next results on the Report Portal page:
Pretty much stuff with different logic is included in the one single test function. So we can move different operations to separate functions:
import logging
from web import OrderingSimulator
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
order_simulator = OrderingSimulator()
def navigate_to_main_page():
logger.info('Main page displayed')
def login():
order_simulator.log_in()
logger.info('User logged in')
def navigate_to_products_page():
products = order_simulator.get_products()
logger.info('Products page opened')
return products
def click_on_product():
product = order_simulator.choose_product()
logger.info("Product click event")
return product
def select_products_count(count):
logger.info(str(count) + " products selected")
def click_cart_button(product, count):
order_simulator.add_product(product, count)
logger.info(str(count) + " products added to the cart")
assert 5 == count
def add_product_to_cart(product_count):
product = click_on_product()
select_products_count(product_count)
click_cart_button(product, product_count)
def pay(total_price):
order_simulator.do_payment(total_price)
logger.info("Successful payment")
def logout():
order_simulator.log_out()
logger.info("User logged out")
def test_order_products():
product_count = 5
price = 3.0
total_price = price * product_count
navigate_to_main_page()
login()
navigate_to_products_page()
add_product_to_cart(product_count)
pay(total_price)
logout()
Much better, but result on the Report Portal looks the same. So we grouped our logic by functions, but we cannot see our grouping on the view. That's a problem. And we can solve it using @step decorator.
In Report Portal Step is a TestItem without statistics that required for splitting large test functions or methods on multiple parts to provide clear and concise view for them. Steps have flexible structure and can be put under other Steps. @step decorator consists of 4 args:
def step(name_source, params=None, status='PASSED', rp_client=None):
"""Nested step report function.
Create a Nested Step inside a test method on Report Portal.
:param name_source: a function or string which will be used as step's name
:param params: nested step parameters which will be reported as the
first step entry. If 'name_source' is a function
reference and this parameter is not specified, they
will be taken from the function.
:param status: the status which will be reported after the step
passed. Can be any of legal Report Portal statuses.
E.G.: PASSED, WARN, INFO, etc. Default value is PASSED
:param rp_client: overrides Report Portal client which will be used in
step reporting
:return: a step context object
"""
pass
So now we can update our test with @step decorators and get a view that matches with our grouping:
import logging
from reportportal_client import step
from web import OrderingSimulator
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
order_simulator = OrderingSimulator()
@step
def navigate_to_main_page():
logger.info('Main page displayed')
@step
def login():
order_simulator.log_in()
logger.info('User logged in')
@step
def navigate_to_products_page():
products = order_simulator.get_products()
logger.info('Products page opened')
return products
@step
def click_on_product():
product = order_simulator.choose_product()
logger.info("Product click event")
return product
@step
def select_products_count(count):
logger.info(str(count) + " products selected")
@step
def click_cart_button(product, count):
order_simulator.add_product(product, count)
logger.info(str(count) + " products added to the cart")
assert 5 == count
@step
def add_product_to_cart(product_count):
product = click_on_product()
select_products_count(product_count)
click_cart_button(product, product_count)
@step
def pay(total_price):
order_simulator.do_payment(total_price)
logger.info("Successful payment")
@step
def logout():
order_simulator.log_out()
logger.info("User logged out")
def test_order_products():
product_count = 5
price = 3.0
total_price = price * product_count
navigate_to_main_page()
login()
navigate_to_products_page()
add_product_to_cart(product_count)
pay(total_price)
logout()
Results on the Report Portal page: