Дефинирайте контекстни променливи в behave python

Понякога трябва да дефинирате стойности динамично (като дата и час сега, произволни низове, произволни цели числа, съдържание на файлове и т.н.) и да ги използвате в различни стъпки, без да сте изрични или твърдо да кодирате стойността.

И така, въпросът ми е как мога да дефинирам променливи вътре в стъпките (правилният начин да го направя), за да използвам тези променливи в следващите стъпки.

Някои примери

Given A random string of length "100" as "my_text"
And I log in to my platform
And I ask to add the following post:
 | title                    | description |
 | Some example of title    | {{my_text}} |
When I submit the post form
Then The posts table shows these posts:
 | title                    | description |
 | Some example of title    | {{my_text}} |
And I delete any post containing in the description "{{my_text}}"

Това е основен пример, който се опитва да обясни защо бих искал да дефинирам променливи на стъпки и да ги запазя в контекста, за да го използвам в следващите стъпки.

Идеята ми беше да модифицирам методите before_step и after_step... за да задам променлива в контекст, за да съхранявам моите персонализирани променливи по следния начин:

def before_step(context):
    if not hasattr(context, 'vars'):
       context.vars = {}

    if hasattr(context, table) and context.table:
       parse_table(context)

def parse_table(context):
    # Here use a regex to check each cell and look for `"{{<identifier>}}"` and if match, replace the cell value by context.vars[identifier] so the step "the posts table shows these posts will never know what is `{{my_text}}` it will be abstract seeing the random string.

Схема на сценарии, използвайте нещо подобно, като дефинирате променливи като "<some_identifier>" и след това за всеки пример заменете стойността в стъпката.

Основно е да се възпроизведе поведението, но за всякакъв вид стъпка, проста или използваща таблици.

Това ли е правилният начин да направите нещо подобно?


person Federico Castro    schedule 07.04.2015    source източник


Отговори (3)


От Behave docs on the context:

Когато behave се стартира в нова функция или сценарий, той добавя нов слой към контекста, позволявайки на новото ниво на дейност да добавя нови стойности или да презапише дефинираните по-рано, за времетраенето на тази дейност. Те могат да се разглеждат като обхвати:

@given('I request a new widget for an account via SOAP')
def step_impl(context):
    client = Client("http://127.0.0.1:8000/soap/")
    // method client.Allocate(...) returns a dict
    context.response = client.Allocate(customer_first='Firstname',
        customer_last='Lastname', colour='red')
    // context vars can be set more directly
    context.new_var = "My new variable!"

@then('I should receive an OK SOAP response')
def step_impl(context):
    eq_(context.response['ok'], 1)
    cnv = str(context.new_var)
    print (f"This is my new variable:'{cnv}'"

Така че стойността може да бъде зададена с помощта на точкова нотация и извлечена същата.

person ingyhere    schedule 20.02.2020

Според моя опит не можете да създадете динамична стойност във файл с функции.
например тази стъпка:
Даден е случаен низ с дължина "100" като "my_text"
Не виждам начин да променя { my_text} всеки път, когато изпълнявате сценария. (не обмисляйте да използвате behave -D за анализиране на стойността на context.config.userdata, мисля, че това също е грешен подход)
Дори схемата на сценария всъщност се разделя на много сценарии. всеки сценарий ще има различна стойност, но стойността на {my_text} вече е дефинирана в таблицата с примери за всеки сценарий.

Начинът, по който една стъпка става динамична, е използването на дефиниция на стъпка (Кодов слой).
Можете да генерирате произволно число в дефиницията на стъпка @given('Произволен низ с дължина "100" като "{my_text}"')
И използвайте context.my_text, за да съхраните създаденото число и да го използвате наоколо.

Също така съм съгласен с Мърфи Менг, че не е необходимо да излагате изрично генерираното произволно число във файла с функции. Знаете коя стъпка ще използва това число, просто използвайте context.my_text в тази стъпка, за да получите стойността. Това е.

person Thach Hoang    schedule 07.12.2018

За да се отговори на този въпрос, трябва да се отбележи:

  • Необходимо ли е данните от теста да се контролират външно? Например, тестовите данни могат да бъдат въведени от командния ред, така че стойността да може да бъде избрана изрично.

Ако отговорът е не, тогава вероятно не трябва да си правим труда да кодираме нищо във файла с функции. И можем да оставим данните, генерирани в една стъпка, да ги запазим в контекст и да имаме достъп отново във всяка следваща стъпка.

Примерът, който мисля, е точно като това, което е описано във въпроса. Интересува ли ни какво произволно текстово съдържание сме генерирали, публикували и проверили? Вероятно не. Тогава не трябва да излагаме такива подробности на потребителя (т.е. файл с функции), тъй като не е важно за поведението, което тестваме.

Ако отговорът е да, имаме нужда от малко хак, за да го осъществим. Преживявам такъв случай. Това, което искам, е да променя тестовите данни, когато стартирам теста, така че да не се налага да ги кодирам твърдо във файловете с функции, както в таблица или схема на сценарий. Как мога да направя това?

Мога да използвам опцията -D в командния ред, за да предам възможно най-много потребителски данни, които след това могат да бъдат достъпни в речника context.config.userdata във всяка стъпка. Ако броят на тестовите данни е много ограничен. Този подход е лесен начин. Но ако наборът от тестови данни съдържа много данни, които никой не иска да въвежда един по един в командния ред, той може да се съхранява външно, например ini файл с имена на секции като testdata_1...testdata_n, и по този начин може да бъде предаден низ от командния ред, който да се използва за адресиране на името на раздела в този конфигурационен файл. И тестовите данни могат да бъдат прочетени или в before_all, или before_scenario и т.н., и да се използват във всички стъпки.

person Murphy Meng    schedule 20.06.2018