Given, When, Then...
The words given, when, then should ring the bell for anybody, who was writing BDD tests. If not, then you should read a recent article of Martin Fowler.
The structure of a test as for BDD has three parts:
-
GIVEN the part, that describes the structure of the system before the tests starts. The test itself "describes" this state with a series of setup commands to move the system under test (SUT) into the state that is prerequisite of the test.
-
WHEN is the part that triggers the SUT. The triggers are usually method calls to the SUT and ideally contains only a few calls that are necessary to test the feature of the system that is the tested feature of the system.
-
THEN test that the state of the SUT has changed appropriately and shows the observable changes that the test is focusing on.
As Martin Fowler writes "Some people like to put Given-When-Then as comments to mark informal blocks inside unit tests." I also followed this approach and I was busy writing //GIVEN
, //WHEN
, //THEN
comments, but I was always bothered by comments. I am not excluding comments from my programming arsenal, but many times when I feel to write comments, especially inline comments, I can find better ways. Many times I find it to be a better approach to move even a single line, not to mention two or more lines, into a separate method with a speaking name and calling the private method from the place where the lines originally were. This proves to be much better in most cases than writing comment on the lines.
What is it then with the //GIVEN
, //WHEN
, //THEN
comments? Is there any way to express the test better?
Certainly there are better ways. One way is to use some framework to express your tests, like Cucumber, or JBehave or if you use some non-Java language some other framework as described on the wiki page of Behavior driven development. I personally recommend to devote the time and learn those frameworks, and use one that fits your taste. Just as in the general case: time invested into testing in any form is never wasted.
Time invested into testing is never wasted.
But what to do if you just write some simple test project. Something of a few classes that does not justify the use of any such test frameworks. Of course, you still need testing, as there is only one project that does not need testing: the null
project (or /dev/null
for old school gentlemen). So you just start a very small project, say a half afternoon, and you start to write your code (of the unit test at first place of course). Should you write //GIVEN
, //WHEN
, //THEN
comments?
Well, your taste. Recently I realized that I can also write the GIVEN
, WHEN
, THEN
as labels in front of the blocks that contain the 'given', 'when' and 'then' code. Do not feel surprised, if you have never heard of labels in Java. Most Java programmers did not. They are stone age residues, totally useless and are kept for compatibility reason. I opt that they are in the language by mistake inherited from C, Perl and other fossils. However, if they are there, why not use them? The example code
@Test
@SuppressWarnings("unused")
public void given_AnACL_when_SubjectQueryAFunction_then_GivesPermisssion() {
final Subject subject;
final AccessControlList acl;
final Function function;
GIVEN: {
subject = mock(Subject.class);
function = mock(Function.class);
acl = new AccessControlList.Builder().add(
new AccessControlElement.Builder().subject(subject)
.function(function).build()).build();
}
final boolean permitted;
WHEN: {
permitted = can(subject).using(acl).execute(function);
}
THEN: {
assertThat(permitted, is(true));
}
}
shows you the idea. Is it better than
@Test
public void given_AnACL_when_SubjectQueryAFunction_then_GivesPermisssion() {
final Subject subject;
final AccessControlList acl;
final Function function;
// GIVEN
subject = mock(Subject.class);
function = mock(Function.class);
acl = new AccessControlList.Builder().add(
new AccessControlElement.Builder().subject(subject)
.function(function).build()).build();
final boolean permitted;
// WHEN
permitted = can(subject).using(acl).execute(function);
// THEN
assertThat(permitted, is(true));
}
? Matter of taste. Your opinion?
Comments imported from Wordpress
lukaseder 2013-12-12 08:18:40
That’s quite clever, Peter! I had never thought of using labels this way.
I love labels, by the way. They’re the window functions / grouping sets of Java. A device whose mystery is only exceeded by its power ;-)
lukaseder 2013-12-12 08:16:39
Well, I think using barely known language elements aren’t good for code readability
Worse than barely known DSLs? :-)
stokito 2013-12-08 11:48:13
I would like to recommend you Spock. It looks like exactly what you need. https://code.google.com/p/spock/wiki/SpockBasics
class HelloSpock extends spock.lang.Specification { def "length of Spock’s and his friends' names"() { expect: name.size() == length
where: name | length "Spock" | 5 "Kirk" | 4 "Scotty" | 6 } }
Norbert Csík 2013-12-07 22:02:20
Well, I think using barely known language elements aren’t good for code readability. However, the structure of the code is better than before. I would prefer the inline comments.
tomekkaczanowski 2014-01-02 12:21:36
Interesting idea to use labels - I have never thought of this. I use inline comments cause my whole team like this, however sometimes blank lines are enough. BTW. If you interested in such things you might enjoy my latests (free) book "Bad Tests, Good Tests" (at http://practicalunittesting.com). It includes many examples of imperfect tests and discusses how they could be improved. Cheers!
Gabriel Kohen 2017-10-30 20:05:16
I would add method-name-tested_ before the test name to easily group and navigate to unit tests for that method.
Comments
Please leave your comments using Disqus, or just press one of the happy faces. If for any reason you do not want to leave a comment here, you can still create a Github ticket.