Python BDD测试所有数据组合

Python BDD Test all data combinations

假设我有两组 BDD 场景的测试数据。

dataX = [A, B, C]

数据 Y = [1, 2, 3, 4]

如果不在场景大纲中明确定义这些组合,我如何运行针对所有 dataX-dataY 组合的场景?

目前,BDD 场景如下所示,如您所见,我明确定义了所有可能的组合。如果值计数 and/or 变量计数增加,事情很快就会变得非常不切实际。为此我正在使用 python-behave library

Scenario Outline: Test all data combinations - <dataX> <dataY>
    Given combination <dataX> <dataY>
    When do stuff with given combination <dataX> <dataY>
    Then check result for <dataX> <dataY>

 Examples: Input
 | dataX | dataY |
 |   A   |   1   |  
 |   A   |   2   | 
 |   A   |   3   | 
 |   A   |   4   | 
 |   B   |   1   |  
 |   B   |   2   | 
 |   B   |   3   | 
 |   B   |   4   | 
 |   C   |   1   |  
 |   C   |   2   | 
 |   C   |   3   | 
 |   C   |   4   | 

请注意,这需要通过场景大纲和示例来完成,以确保所有测试数据覆盖。使用简单的场景并可能在单个测试下测试所有组合是不够的,因为这通常意味着测试在遇到第一个故障时停止,跳过任何剩余的测试数据。

我不知道这是否是您要查找的内容,但您可以执行如下一般情况:

Feature: Test
Scenario: Test all data combinations
    Given combination data is loaded
    When combinations are processed
    Then display results

这将允许您在第一步加载数据(例如从外部文件)并在 When 步骤执行组合过程(可能调用其他步骤)。

步骤实施可能如下所示:

from behave import *
from steps import data

@given('combination data is loaded')
def step_impl(context):
    context.data_x = getattr(data, "dataX")
    context.data_y = getattr(data, "dataY")
    print(context.data_x)
    print(context.data_y)

@when('combinations are processed')
def step_impl(context):
    for x in context.data_x:
        for y in context.data_y:
            context.execute_steps(
                """
                When process combination {x} and {y}
                Then check result for given combination
                """.format(x=x, y=y)
            )

@then('display results')
def step_impl(context):
    print(context.results)

@when('process combination {x} and {y}')
def step_impl(context, x, y):
    context.x = x
    context.y = y

@then('check result for given combination')
def step_impl(context):
    context.results.append('.'.join([context.x, context.y]))

运行 这给出:

>>behave --no-capture
Feature: Test # test.feature:1

  Scenario: Test all data combinations  # test.feature:2
    Given combination data is loaded    # steps/step_implementation.py:4
['A', 'B', 'C']
[1, 2, 3, 4]
    When combinations are processed     # steps/step_implementation.py:20
    Then display results                # steps/step_implementation.py:31
['A.1', 'A.2', 'A.3', 'A.4', 'B.1', 'B.2', 'B.3', 'B.4', 'C.1', 'C.2', 'C.3', 'C.4']

1 feature passed, 0 failed, 0 skipped
1 scenario passed, 0 failed, 0 skipped
3 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.016s

我会以不同的方式处理这个问题。 BDD 的目的是检查应用程序的行为,这可以通过使用测试不同业务需求的少数特定数据集进行测试来完成。例如,如果要求将 2 个数字相加,您将使用不同的数据集(如正数、负数、小数)对其进行测试。您不会测试所有可能的数字组合。

但是,如果您的应用程序处理每个数据的方式与“是”不同,则您必须测试所有数据组合。在这种情况下,最好定义大型数据集,而不是编写代码来生成数据集。原因是,最好明确说明您的应用程序将要处理的内容作为 BDD 步骤的一部分,而不是埋在代码中,因为这只有团队的技术成员才能理解。这违背了使用 BDD 的目的。

对于非常大的数据集,您可以考虑维护 excel 中的数据。我已经展示了如何在 NoCodeBDD 中完成此操作(免责声明:我是 NoCodeBDD 的创始人)https://nocodebdd.live/examples-using-excel。您可以在 Cucumber 中执行相同的操作,但您必须编写代码来读取 excel.

在深入了解 behave 库实现之后,我找到了一些可以用来执行此操作的方法:以编程方式构建 Examples table。我的用例是全部需要测试的大量数据组合。

这进入 environment.py:

from behave.model import Scenario, Examples, Table
from itertools import product

def before_feature(context, feature):
    ...
    # data for each column for the Examples table; the way you get this is based on your specific case;
    # you can read it from a file or generate it etc.; this here is merely an example
    data_x = [data for test column dataX here]
    data_y = [data for test column dataY here]

    # create data tuples aka table rows; we will add these a bit later to the Examples table
    # the way you build this is also specific to your case; I am using itertools.product for a quick way to get all possible pairs
    all_data_pairs = [(dx, dy) for dx, dy in product(data_x, data_y)]

    # identify the behave.model.Examples object we will populate
    example: Examples = next(sc.examples[0] for sc in feature.scenarios if
                                     sc.name == 'Test all data combinations - <dataX> <dataY>')

    # Examples consists, amongst other things, of an object of type behave.model.Table
    test_table: Table = example.table
    
    # add test data to the Examples table, row by row
    for row in all_data_pairs:
        test_table.add_row(row)

这将确保方案 "Test all data combinations - <dataX> <dataY>" 断言 所有 测试行。第一次失败后不会停止。