In “Given-When-Then” style BDD tests, is it OK to have multiple “When”s conjoined with an “And”?

1.4k views Asked by At

I read Bob Martin's brilliant article on how "Given-When-Then" can actual be compared to an FSM. It got me thinking. Is it OK for a BDD test to have multiple "When"s?

For eg.

GIVEN my system is in a defined state
WHEN an event A occurs
 AND an event B occurs
 AND an event C occurs
THEN my system should behave in this manner

I personally think these should be 3 different tests for good separation of intent. But other than that, are there any compelling reasons for or against this approach?

3

There are 3 answers

0
Laurent Bristiel On

When multiple steps (WHEN) are needed before you do your actual assertion (THEN), I prefer to group them in the initial condition part (GIVEN) and keep only one in the WHEN section. This kind of shows that the event that really triggers the "action" of my SUT is this one, and that the previous one are more steps to get there.

Your test would become:

GIVEN my system is in a defined state
 AND an event A occurs
 AND an event B occurs
WHEN an event C occurs
THEN my system should behave in this manner

but this is more of a personal preference I guess.

0
Bryan Oakley On

If you truly need to test that a system behaves in a particular manner under those specific conditions, it's a perfectly acceptable way to write a test.

0
Zoltán Kozma On

I found that the other limiting factor could be in an E2E testing scenario that you would like to reuse a statement multiple times. In my case the BDD framework of my choice(pytest_bdd) is implemented in a way that a given statement can have a singular return value and it maps the then input parameters automagically by the name of the function that was mapped to the given step. Now this design prevents reusability whereas in my case I wanted that. In short I needed to create objects and add them to a sequence object provided by another given statement. The way I worked around this limitation is by using a test fixture(which I named test_context), which was a python dictionary(a hashmap) and used when statements that don't have same singular requirement so the '(when)add object to sequence' step looked up the sequence in the context and appended the object in question to it. So now I could reuse the add object to sequence action multiple times.

This requirement was tricky because BDD aims to be descriptive. So I could have used a single given statement with the pickled memory map of the sequence object that I wanted to perform test action on. BUT would it have been useful? I think not. I needed to get the sequence constructed first and that needed reusable statements. And although this is not in the BDD bible I think in the end it is a practical and pragmatic solution to a very real E2E descriptive testing problem.