Search code examples
pythoncucumberbddgherkinpython-behave

Python BDD Test all data combinations


Say I have two sets of test data for a BDD scenario.

dataX = [A, B, C]

dataY = [1, 2, 3, 4]

How can I run a scenario against all combinations of dataX-dataY, without explicitly defining these combinations in the scenario outline?

Currently, the BDD scenario looks something like the below, and as you can see I am explicitly defining all possible combinations. Things can become very impractical very quickly if the value count and/or variable count increase. Am using the python-behave library for this.

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   | 

Note this needs to be done via Scenario Outline & Examples to ensure all test data coverage. Using a simple Scenario and potentially testing all combinations under a single test is not sufficient, as it typically means the test stops at the first failure encountered, skipping any remaining test data.


Solution

  • After going through the guts of the behave library implementation, I was able to find some methods that one can use to do just this: build the Examples table programatically. My use case is the large number of data combinations that all need testing.

    This goes in 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)
    

    This will ensure scenario "Test all data combinations - <dataX> <dataY>" asserts all test rows. It will NOT stop after the first failure.