9

有时,您需要动态定义值(例如现在的日期时间、随机字符串、随机整数、文件内容等)并在不同的步骤中使用它们,而无需显式或硬编码值。

所以,我的问题是如何在步骤中定义变量(正确的方法)以在以下步骤中使用这些变量。

一些例子

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>",然后为每个示例替换步骤中的值。

它基本上是为了重现行为,但对于任何类型的步骤,简单或使用表格。

这是做这样的事情的正确方法吗?

4

3 回答 3

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}'"

因此,可以使用点表示法设置值并检索相同的值。

于 2020-02-20T08:21:25.620 回答
0

根据我的经验,您无法在功能文件中创建动态值。
例如,这一步:
给定一个长度为“100”的随机字符串作为“my_text”
,每次运行场景时,我都看不到任何改变 {my_text} 的方法。(不考虑使用behavior -D 来解析context.config.userdata的值,我觉得这也是一种错误的做法)
即使是Scenario Outline,它实际上也拆分为很多场景。每个场景都有不同的值,但 {my_text} 的值已经在每个场景的示例表中定义。

使步骤动态化的方法是使用步骤定义(代码层)。
您可以在步骤定义中生成一个随机数 @given('A random string of length "100" as "{my_text}"')
并使用 context.my_text 存储创建的数字并使用它。

我也同意 Murphy Meng 的观点,即您不需要在功能文件中显式公开生成的随机数。您知道哪个步骤将使用该数字,只需在该步骤中使用 context.my_text 即可获取值。而已。

于 2018-12-07T17:21:23.963 回答
0

要回答这个问题,需要注意:

  • 测试数据是否需要外部控制?例如,可以从命令行输入测试数据,以便明确选择值。

如果答案是否定的,那么我们可能不应该在功能文件中硬编码任何内容。我们可以保留一步生成的数据,将其保存在上下文中,然后在任何后续步骤中再次访问。

我能想到的例子与问题描述的完全一样。我们关心我们生成、发布和验证的随机文本内容吗?可能不是。那么我们不应该将这些细节暴露给用户(即特征文件),因为它对我们正在测试的行为并不重要。

如果答案是肯定的,我们确实需要一些技巧来实现它。我正在经历这样的案例。我想要的是在运行测试时更改测试数据,这样我就不必像在表格或场景大纲中那样在功能文件中硬编码它们。我怎样才能做到这一点?

我可以在命令行中使用 -D 选项来传递尽可能多的用户数据,然后可以在任何步骤中在 context.config.userdata 字典中访问这些数据。如果测试数据的数量非常有限。这种方法是一种简单的方法。但是如果测试数据集包含很多没人要在命令行中逐一键入的数据,则可以将其存储在外部,例如,一个ini文件,其节名称为testdata_1...testdata_n,因此可以传递一个字符串从命令行输入用于寻址此配置文件中的部分名称。并且可以在 before_all 或 before_scenario 等中读取测试数据,并在所有步骤中使用。

于 2018-06-20T17:05:28.373 回答