2014-05-18 15 views
6

Korzystanie z doskonałej struktury Behave, ale kłopot z moim brakiem umiejętności OOP.Dodawanie wspólnych atrybutów do metody Behave

Zachowanie ma wbudowaną przestrzeń nazw kontekstu, w której obiekty mogą być współużytkowane między krokami wykonania testu. Po zainicjowaniu sesji WebDriver, przechodzę dalej między moimi krokami, używając tego context do przechowywania wszystkiego. Funkcjonalność jest w porządku, ale jak widać poniżej, nie jest to nic innego jak SUCHEGO.

Jak/gdzie mogę jednorazowo dodać te atrybuty do step_impl() lub context?

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/") 
+1

Czy pytanie tylko w jaki sposób uniknąć wszystkich rozpakowaniu z ' kontekst "w każdej funkcji' step_impl'? Powiedziałbym, że możesz wyciąć kilka z nich po prostu pomijając przedmioty, których nie będziesz używać później (np. 'Xenv' wszędzie,' wait' i 'expected_conditions' w ostatniej wersji). Poza tym możesz pominąć rozpakowywanie i po prostu użyć atrybutów kontekstu bezpośrednio, np. 'context.driver.get (cokolwiek)'. Wiem niewiele o Behave, więc nie jestem pewien, czy to jest odpowiedź. – Blckknght

+0

Dzięki. Tak, aby uniknąć rozpakowywanie * i * uniknąć powielania poprzez wywołanie 'context.attribute.something' za każdym razem, z których żadna nie czują się bardzo pythonic –

Odpowiedz

6

Przede wszystkim można po prostu pominąć ten rozpakowywanie i używać context atrybuty wszędzie, jak context.driver.get("http://domain.com")

If nie lubisz tego i naprawdę chcesz mieć zmienne lokalne można użyć krotki rozpakowaniu aby kod trochę lepiej:

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

Można czynnik poza domyślną listę atrybutów, takich jak to, ale sprawia, że ​​cała sprawa trochę niejawny:

import operator 

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

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

Jeśli nadal nie podoba ci się to, możesz sfałszować z globals(). Na przykład funkcja skrzyni tak:

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

i używać go w kroku:

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

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

To zmniejszy powtórzeń w kodzie, ale jest bardzo niejawne i może być niebezpieczne. Więc nie jest zalecane, aby to robić w ten sposób.

Po prostu rozpakowuję tuple. Jest prosty i wyraźny, więc nie spowoduje dodatkowych błędów.

+0

Dzięki, miał nadzieję wykorzystać rozpakowywanie krotka, ale w tym przypadku otrzymaliśmy:' powrotu [ getattr (kontekst, pole) dla pola w kontekście] TypeError: Obiekt 'Context' nie jest iterable' –

+1

Tak, przepraszam. Zmieniłem odpowiedź. To musi być 'field_list', nie' context' –

+0

zauważyć, że w ostatnich wersjach Pythona nie można (skutecznie) przypisać do wartości zwracanej 'mieszkańców()'. Słownik zwracany przez 'locals()' jest kopią zmiennych lokalnych w czasie jej wywoływania, ale wprowadzone zmiany nie zostaną odzwierciedlone w rzeczywistej lokalnej przestrzeni nazw. – Blckknght

2

Można zdefiniować dekorator, że 'rozpakowuje' kontekst dla Ciebie i przekazuje wartości 'rozpakowane' jako argumenty

environment.py

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

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

test.feature

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

Krok.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 
1

trzymać się reguły DRY Zwykle używam:
* Tło opowieści: http://pythonhosted.org/behave/gherkin.html#background
* lub kontroli w zakresie ochrony środowiska: http://pythonhosted.org/behave/tutorial.html#environmental-controls

+0

Oto przykładowy plik funkcja [twilio_handler.feature] (https://github.com/kowalcj0/flaskrilio/blob/master/flaskrilio/features/twilio_handler.feature) z historią w tle i tutaj: [twilio_handler_steps.py] (https : //github.com/kowalcj0/flaskrilio/blob/master/flaskrilio/features/steps/twilio_handler_steps.py) to implementacja jego kroków. – kowalcj0

Powiązane problemy