2014-05-18 17 views
6

Utilizzo del grande framework Behave, ma con problemi con la mia mancanza di competenze OOP.Aggiunta di attributi comuni a un metodo Behave

Behave dispone di uno spazio dei nomi di contesto integrato in cui è possibile condividere gli oggetti tra i passaggi di esecuzione del test. Dopo aver inizializzato la mia sessione di WebDriver, continuo a passarlo tra i miei passi usando questo context per contenere tutto. Funzionalità va bene, ma come potete vedere qui sotto, è tutto tranne che ASCIUTTO.

Come/dove posso aggiungere questi attributi allo step_impl() o context una volta sola?

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

è la domanda solo come evitare tutto il disimballaggio da ' contesto' in ciascuna funzione 'step_impl'? Direi che potresti tagliarne un po 'saltando gli oggetti che non userete più tardi (ad esempio 'xenv' ovunque,' wait' e 'expected_conditions' nell'ultima versione). Oltre a ciò, è possibile saltare alcuni decompressione e utilizzare semplicemente gli attributi del contesto direttamente, ad es. 'Context.driver.get (qualunque)'. So poco di Behave, quindi non sono sicuro che questa sia una risposta. – Blckknght

+0

Grazie. Sì, per evitare tutto il disimballaggio * e * evitare la duplicazione chiamando 'context.attribute.something' ogni volta, nessuno dei quali si sente molto Pythonic –

risposta

6

Prima di tutto si può semplicemente saltare questo disimballaggio e utilizzare context attributi ovunque, come context.driver.get("http://domain.com")

Se non ti piace e vuoi davvero di avere variabili locali che è possibile utilizzare tuple disimballaggio per rendere il codice po 'meglio:

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

Si può scomporre elenco predefinito di attributi del genere, ma che rende il tutto un po' implicita:

import operator 

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

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

Se ancora non ti piace, puoi manipolare con globals(). Per esempio cassa di una funzione del genere:

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

e utilizzarlo nel vostro passo:

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

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

Ciò riduce la ripetizione nel codice, ma è molto implicita e potrebbe essere pericoloso. Quindi non è raccomandato farlo in quel modo.

Vorrei solo usare la tupla per decomprimere. È semplice ed esplicito, quindi non causerà ulteriori errori.

+0

Grazie, speravo di usare la tupla decompressione, ma in questo caso ho ricevuto:' return [ getattr (context, field) per campo nel contesto] TypeError: 'Context' object is not iterable ' –

+1

Sì, mi dispiace. Ho modificato la risposta. Deve essere 'field_list', non' context' –

+0

Nota che nelle versioni recenti di Python non puoi (utilmente) assegnare al valore restituito di 'locals()'. Il dizionario restituito da 'locals()' è una copia delle variabili locali nel momento in cui viene chiamato, ma le modifiche apportate non si rifletteranno nello spazio dei nomi locale effettivo. – Blckknght

2

Si potrebbe definire un decoratore che 'spacchetta' il contesto per voi e passa i valori 'spacchettato' come argomenti:

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" 

passaggio.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

a bastone per la regola DRY Io di solito uso:
* Storie di casi: http://pythonhosted.org/behave/gherkin.html#background
* o controlli ambientali: http://pythonhosted.org/behave/tutorial.html#environmental-controls

+0

Ecco un file delle caratteristiche di esempio [twilio_handler.feature] (https://github.com/kowalcj0/flaskrilio/blob/master/flaskrilio/features/twilio_handler.feature) con una storia di background e qui: [twilio_handler_steps.py] (https : //github.com/kowalcj0/flaskrilio/blob/master/flaskrilio/features/steps/twilio_handler_steps.py) è la sua implementazione dei passaggi. – kowalcj0

Problemi correlati