Get Your Software Covered Using Covering Arrays

For software systems with any non-trivial number of parameters, exhaustively testing all possible combinations of parameter values is not feasible. For example, if we have 10 parameters (k = 10) that each have 10 possible values (v = 10), the number of all possibilities is vk=1010=10billionv^k=10^{10} = {10}_{billion}, thus requiring 10 billion tests for complete coverage.

Given that exhaustive testing might not be practical, a covering array (CA) could give us a much smaller number of tests if we choose to check all possible interactions only between some fixed number of parameters at least once, where an interaction is some specific combination, where order does not matter, of some t number of parameters, covering all possible values that each selected parameter could have.

The US National Institute of Standards and Technology (NIST) has an excellent Introduction to Covering Arrays page, if you are not familiar with them. Note that in the literature, a covering array is usually defined as CA(t,k,v)CA(t,k,v) , where t is the strength of the array, k is the number of parameters, and v is the number of values. In most cases, it is assumed that each parameter has the same number of values, v, and such arrays are referred to as uniform covering arrays.

The NIST, upon request, provides a tool called Advanced Combinatorial Testing System (ACTS), which runs on Java platforms and can be used to generate covering arrays to ensure t-way coverage of input parameter values using advanced algorithms such as IPOG-F. However, for tests developed in Python, a pure Python implementation would be preferred if the number of parameters is not too large. If the number of parameters is large, then you can use ACTS or check if one of the NIST-provided precomputed covering arrays generated by IPOG-F can be applied.

TestFlows.com Open-Source Testing Framework, starting with version 2.1.5, provides a CoveringArray class to allow you to calculate a covering array for some k parameters having the same or different number of possible values. Therefore, it allows you to generate both uniform and non-uniform covering arrays. The class uses IPOG, a pure Python implementation of an in-parameter-order algorithm as described in IPOG: A General Strategy for T-Way Software Testing by Yu Lei et al.

The CoveringArray(parameters, strength=2) class is provided by the testflows.combinatorics module and takes the following arguments:

  • parameters specifies parameter names and their possible values as a dict[str, list[value]], where key is the parameter name and value is a list of possible values for a given parameter.
  • strength specifies the strength t of the covering array that indicates the number of parameters in each combination, for which all possible interactions will be checked. If strength equals the number of parameters, then you get the exhaustive case.

The return value of the CoveringArray(parameters, strength=2) is a CoveringArray object that is an iterable of tests, where each test is a dictionary, with each key being the parameter name and its value being the parameter value.

For example,

1
2
3
4
5
from testflows.combinatorics import CoveringArray

parameters = {"a": [0, 1], "b": ["a", "b"], "c": [0, 1, 2], "d": ["d0", "d1"]}

print(CoveringArray(parameters, strength=2))

Gives the following output:

1
2
3
4
5
6
7
8
9
10
11
CoveringArray({'a': [0, 1], 'b': ['a', 'b'], 'c': [0, 1, 2], 'd': ['d0', 'd1']},2)[
6
a b c d
-------
0 b 2 d1
0 a 1 d0
1 b 1 d1
1 a 2 d0
0 b 0 d0
1 a 0 d1
]

Given that in the example above, the strength = 2, all possible 2-way (pairwise) combinations of parameters a, b, c, and d are the following:

1
[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

The six tests that make up the covering array cover all the possible interactions between the values of each of these parameter combinations. For example, the ('a', 'b') parameter combination covers all possible combinations of the values that parameters a and b can take.

Given that parameter a can have values [0, 1] and parameter b can have values ['a', 'b'], all possible interactions are the following:

1
[(0, 'a'), (0, 'b'), (1, 'a'), (1, 'b')]

where the first element of each tuple corresponds to the value of the parameter a, and the second element corresponds to the value of the parameter b.

Examining the covering array above, we can see that all possible combinations, also referred to as interactions, of parameters a and b are indeed covered at least once. The same check can be done for other parameter combinations.

Checking the Covering Array

The CoveringArray.check() method can be used to verify that the tests inside the covering array cover all possible t-way interactions at least once and thus meet the definition of a covering array.

For example,

1
2
3
4
5
6
from testflows.combinatorics import CoveringArray

parameters = {"a": [0, 1], "b": ["a", "b"], "c": [0, 1, 2], "d": ["d0", "d1"]}
tests = CoveringArray(parameters, strength=2)

print(tests.check())

This is handy to confirm that the covering array that was calculated is valid.

Dumping the Covering Array

The CoveringArray object implements a custom __str__ method, and therefore it can be easily converted into a string representation similar to the format used in the NIST covering array tables.

For example,

1
print(CoveringArray(parameters, strength=2))
1
2
3
4
5
6
7
8
9
10
11
CoveringArray({'a': [0, 1], 'b': ['a', 'b'], 'c': [0, 1, 2], 'd': ['d0', 'd1']},2)[
6
a b c d
-------
0 b 2 d1
0 a 1 d0
1 b 1 d1
1 a 2 d0
0 b 0 d0
1 a 0 d1
]

Dumping covering arrays is useful for debugging and to get a general understanding, and the NIST-like format allows you to share it easily with your colleagues.

Wrapping Up

Combinatorial testing is an exciting topic, and in this article, I have introduced you to covering arrays and shown you how the new CoveringArray class allows you to calculate covering arrays for your tests. We have looked at how you can generate, check, and dump covering arrays. Covering arrays are critical for combinatorial testing, and TestFlows.com Open-Source Testing Framework now brings them to your test programs without using any third-party libraries.

If you are interested in seeing how you can implement your combinatorial tests with the TestFlows.com open-source testing framework, check out the Combinatorial Tests section in the Handbook. Until next time, happy combinatorial testing using covering arrays!