tl;dr you can use labels to clarify a given-when-then style of testing.
What is given-when-then?
given-when-then is a commonly used style of specifying system behaviour in which your tests are split into three sections.
- Given is the section that lays out the pre-conditions for the test, ie whatever state you're assuming the world to be in before you start.
- The When clause performs the action being tested.
- The Then statement checks that the post condition holds. This is usually in the form of asserting values or checking interaction with mocks.
It's not always that case that you need to have three sections in the code of every test. For example your given section might be covered by a common setUp
method. I think it's a good idea to follow the pattern and split up the different sections because it allows you to clearly see the wood from the trees.
Using labels with Junit
In some projects I've been experimenting with going a bit further than just splitting out given/when/then and using Java labels in order to lay out the different sections of the test to make things really clear [0]. The following code snippet shows how you might implement that with Junit.
Cafe cafe = new Cafe(); @Test public void cafeShouldNeverServeCoffeeItDoesntHave() { Given: cafe.setCoffeesRemaining(1); When: cafe.serveCoffee(); Then: assertFalse(cafe.canServeCoffee()); }
This is a very simple example just to demonstrate the layout. Our test checks that the Cafe
never serves coffee which it doesn't have. There is a clear demarcation of the three sections of code by the labels. It's a little unusual to see labels used like this - they are most commonly used in Java as a way to break out of nested loops in one go. Of course there is no real reason not to use them like this, it's just a stylistic matter and there is no semantic difference between the code with and without the labels.
Using labels with Lambda Behave
While I'm sure most Java developers use Junit, I recently released a new library called Lambda Behave. This is designed to be a modern testing and behavioural specification framework for Java 8 which makes it easier to write fluent and readable tests. In lambda-behave you write tests by listing out a descriptive string instead of a restrictive method name and describe the body of the test in a lambda expression. I've found tests written in this style are much easier to read.
You can use the same given/when/then label style within lambda-behave specs, as the following code sample shows:
describe("a cafe", it -> { Cafe cafe = new Cafe(); it.should("never serve coffee it doesn't have", expect -> { Given: cafe.setCoffeesRemaining(1); When: cafe.serveCoffee(); Then: expect.that(cafe.canServeCoffee()).is(false); }); });
Limitations & Alternatives
The biggest annoyance of using labels in this way is that, for a reason unknown to me, you can't write a label before a variable declaration statement in Java. This means that if you want to start your Given:
clause using a new variable then you need to hoist the variable declaration to the top of the block or a to a field. I've not found this to be a big problem and in fact the hoisting can clean things up even further.
An alternative, and probably more common, approach is to use comments to denote given/when/then clauses. I think the choice between the two is primarily stylistic rather than substantive. In both cases you're just writing some explanatory text rather than baking the feature into your testing framework as things like Cucumber and JBehave do. I think the idea of using labels as individual comments is suitable if you've agreed a convention within your team to do so and if you want to have these labels stand out more than regular comments.
Some people use alternative patterns to given/when/then that are similar, but have more phases such as the four phase test approach or even different names such as Arrange, Act, Assert. It's possible to use a label based or a comment based convention with these styles as well.
Conclusions
I've put the example code up on github if anyone wants to have a look or a play in their IDE. There's not much code because they are just very simple examples but it might be helpful to show that there's no magic going on!
I've shown how you can use labels to clarify the intent of blocks of code in this blog post and hopefully it's a technique which people find useful and helpful. Regardless of whether you use labels to implement given-when-then or not I hope people write their tests following some kind of convention. It really makes what is going on a lot clearer. I'm sure some people have opinions on the matter, so let me know it you think it's a good idea or not?
Thanks to Raoul Gabriel Urma, Chris West and James Ross for comments on the blog post.
[0] I /think/ that I got the idea from Jose Llarena after talking to him at an LJC event, so thank Jose!