Using the great Behave framework, but having trouble with my lack of OOP skills.
Behave has an inbuilt context namespace where objects can be shared between test execution steps. After initializing my WebDriver session, I keep passing it between my steps using this context
to hold everything. Functionality is fine, but as you can see below, it is anything but DRY.
How/where can I add these attributes to the step_impl()
or context
once only?
environment.py
from selenium import webdriver
def before_feature(context, scenario):
"""Initialize WebDriver instance"""
driver = webdriver.PhantomJS(service_args=service_args, desired_capabilities=dcap)
"""
Do my login thing..
"""
context.driver = driver
context.wait = wait
context.expected_conditions = expected_conditions
context.xenv = env_data
steps.py
@given('that I have opened the blah page')
def step_impl(context):
driver = context.driver
wait = context.wait
expected_conditions = context.expected_conditions
xenv = context.xenv
driver.get("http://domain.com")
driver.find_element_by_link_text("blah").click()
wait.until(expected_conditions.title_contains("Blah page"))
@given(u'am on the yada subpage')
def step_impl(context):
driver = context.driver
wait = context.wait
expected_conditions = context.expected_conditions
xenv = context.xenv
if driver.title is not "MySubPage/":
driver.get("http://domain.MySubPage/")
wait.until(expected_conditions.title_contains("Blah | SubPage"))
@given(u'that I have gone to another page')
def step_impl(context):
driver = context.driver
wait = context.wait
expected_conditions = context.expected_conditions
xenv = context.xenv
driver.get("http://domain.com/MyOtherPahge/")
First of all you can just skip this unpacking and use context
attributes everywhere, like context.driver.get("http://domain.com")
If you don't like it and you really want to have local variables you can use tuple unpacking to make code little better:
import operator
def example_step(context):
driver, xenv = operator.attrgetter('driver', 'xenv')(context)
You can factor out default list of attributes like that, but that makes the whole thing a little bit implicit:
import operator
def unpack(context, field_list=('driver', 'xenv')):
return operator.attrgetter(*field_list)(context)
def example_step(context):
driver, xenv = unpack(context)
If you still don't like that you can mangle with globals()
. For example crate a function like that:
def unpack(context, loc, field_list):
for field in field_list:
loc[field] = getattr(context, field, None)
And use it in your step:
def example_step(context):
unpack(context, globals(), ('driver', 'xenv'))
# now you can use driver and xenv local variables
driver.get('http://domain.com')
This will reduce repetition in your code, but it is very implicit and could be dangerous. So it's not recommended to do it like that.
I'd just use tuple unpacking. It is simple and explicit so won't cause additional errors.