Определить контекстные переменные в поведении Python

Иногда вам нужно определить значения динамически (например, datetime now, случайные строки, случайные целые числа, содержимое файла и т. д.) и использовать их на разных этапах без явного или жесткого кодирования значения.

Итак, мой вопрос заключается в том, как я могу определить переменные внутри шагов (правильный способ сделать это), чтобы использовать эти переменные в следующих шагах.

Пример

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)


Из Поведение документов в контексте:

Когда поведение запускается в новой функции или сценарии, оно добавляет новый слой в контекст, позволяя новому уровню активности добавлять новые значения или перезаписывать ранее определенные на время действия. Их можно рассматривать как области действия:

@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} каждый раз, когда вы запускаете сценарий. (не рассматривайте возможность использования поведения -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