7

使用出色的Behave框架,但因缺乏 OOP 技能而遇到麻烦。

Behave 有一个内置的上下文命名空间,可以在其中在测试执行步骤之间共享对象。初始化我的 WebDriver 会话后,我一直在我的步骤之间传递它,使用它context来保存所有内容。功能很好,但正如您在下面看到的,它绝不是 DRY。

我如何/在哪里可以将这些属性添加到step_impl()orcontext一次?

环境.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

步骤.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/")
4

3 回答 3

6

首先,您可以跳过此解包并context在任何地方使用属性,例如context.driver.get("http://domain.com")

如果你不喜欢它并且你真的想要局部变量,你可以使用元组解包来使代码更好一点:

import operator
def example_step(context):
    driver, xenv = operator.attrgetter('driver', 'xenv')(context)

您可以像这样排除默认属性列表,但这会使整个事情变得有点隐含:

import operator

def unpack(context, field_list=('driver', 'xenv')):
    return operator.attrgetter(*field_list)(context)

def example_step(context):
    driver, xenv = unpack(context)

如果您仍然不喜欢这样,您可以使用globals(). 例如创建一个这样的函数:

def unpack(context, loc, field_list):
    for field in field_list:
        loc[field]  = getattr(context, field, None)

并在您的步骤中使用它:

def example_step(context):
    unpack(context, globals(), ('driver', 'xenv'))

    # now you can use driver and xenv local variables
    driver.get('http://domain.com')

这将减少代码中的重复,但它非常隐含并且可能很危险。所以不建议这样做。

我只是使用元组解包。它简单明了,因此不会导致额外的错误。

于 2014-05-21T06:37:18.500 回答
2

您可以定义一个装饰器,为您“解包”上下文并将“解包”值作为参数传递:

环境.py

def before_feature(context, feature):
    context.spam = 'spam'

def after_feature(context, feature):
    del context.spam

测试功能

Scenario: Test global env
  Then spam should be "spam"

步骤.py

def add_context_attrs(func):
    @functools.wraps(func)  # wrap it neatly
    def wrapper(context, *args, **kwargs):  # accept arbitrary args/kwargs
        kwargs['spam'] = context.spam  # unpack 'spam' and add it to the kwargs
        return func(context, *args, **kwargs)  # call the wrapped function
    return wrapper

@step('spam should be "{val}"')
@add_context_attrs
def assert_spam(context, val, spam):
    assert spam == val
于 2014-05-21T06:59:07.950 回答
1

为了遵守我通常使用的 DRY 规则:
* 背景故事: http: //pythonhosted.org/behave/gherkin.html#background
* 或环境控制: http: //pythonhosted.org/behave/tutorial.html#environmental-控制

于 2014-06-09T20:26:24.127 回答