Unit Testing – How to Test Boolean Function with Many Permutations

unit testing

When I write an unit test I usually provide a context (plain object or mocked/stubbed object) that I setup in some ways and then I can run assert statement on the context:

note: code is in pseudo-code; groovy like syntax:

test myTest() {
  def o = getTestContext();
  o.string = "testme"
  o.number = "2"
  assert o.mult() == "testme testme" 
}

But how to organize the test when you need to test a complex boolean expression that takes many parameters ?

EDIT: I have replaced the one line expression with something more readable to avoid confusion.

//this is not a real class, this is an example. Naming is bad, for conciseness sake
//the expression is coming from randomness realm, so it is probably refactorable and simplifiable, but complex real world expression still exists.
enum Type {X,Y,Z}
class C {
  boolean a,b,c,d;
  Type t;


  boolean isEnabled(boolean anotherFlag) {

    def condition1 = (a || b)
    def condition2 = (c && d)
    def goodType1 = t == X || t == Y
    def goodType2 = anotherFlag && t == Z || t == Z && !condition1 

    return (  condition1  || condition2 ) && (goodType1 || goodType2) 
  }
}

All tests for this kind of methods I've read so far are very verbose, not complete and hard to understand.

And it is quite a shame that such a small line of code, even if it is 'complex', generates awful tests.

I've tried to break the boolean expression into smaller sub methods, but sometime it is not so convenient and the permutation count is still high. I also usually break the expression into intermediate variables, but this is not helping in unit test world…

How should I test something like this to have test code matching the briefness of the tested code and the completeness that must assert that my code works as expected ?

Edit: about the retained solution.

Refactoring is indeed a way to go, but I really don't want to 'unroll' all combinations manually in my tests: it is verbose, ugly and hard to understand.

However I'll keep this answer as a preliminary mandatory step: break the expression into smaller pieces before anything else.

Once the refactoring is done and the test still result in combinatory tests, then I'll use the TruthTable solution proposed. I'll just generate the combinations and not declare everything.

I found this interesting, but outdated, article about test combination in Groovy.
The tool they spoke about is out of search engine radar, so it must be dead !
However I'll use the same pattern:

assertThat(permutations, expectations, instanceObject)

Where

  • permutation is all possible values to assign to properties in a 'condensed map': (a:[true, false], b:[true, false], …)
  • expectation is all combinations that return a specific value, all other combination will be checked against a default value.

Best Answer

One quite intuitive way to handle this is to code a truth table into your test so you have something like:

//last in tuple is expected result, rest are inputs
test date = new List<Tuple<bool,bool,bool,bool,string>>()
{
   {true,true,true,true,"foo"}
   {true,true,true,false,"bar"}
   etc...
}

i.e. a data driven test. For big table you can move this to a data file which you slurp up. The test itself then simply needs to iterate over the table and plug the inputs in and check the expected output.

This also hints at a possible refactoring of the code. An input of Tuple<bool,bool> is essentially the same as an enum with 4 possible values.