Contents[Hide]

1.  BDD Style Cgreen

As mentioned earlier, Cgreen also supports the behaviour driven style of test driving code. The thinking behind BDD is that we don’t really want to test anything, if we just could specify the behaviour of our code and ensure that it actually behaves this way we would be fine.

This might seem like an age old dream, but when you think about it, there is actually very little difference in the mechanics from TDD. First we write how we want it, then implement it. But the small change in wording, from `test´ to `behaviour´, from `test that´ to `ensure that´, makes a huge difference in thinking, and also very often in quality of the resulting code.

1.1.  The SUT

Since BDD talks about behaviour, there has to be something that we can talk about as having the wanted behaviour. This is usually called the SUT, the Subject Under Test. Cgreen in BDD mode requires that you define a name for it.

#include <cgreen/cgreen.h>
Describe(SUT);

Since CGreen supports C++ there you naturally have the objects and also the Subject Under Test, which usually is a class. But in plain C you will have to think about what is actually the "subject" under test. E.g. in sort.c you might see

#include <cgreen/cgreen.h>
Describe(Sorter);

Ensure(Sorter, can_sort_an_empty_list) {
  assert_that(sorter(NULL), is_null);
}

In this example you can clearly see what difference BDD style makes when it comes to naming. Convention, and natural language, dictates that typical names for what TDD would call tests, now starts with can or finds or other verbs, which makes the specification so much easier to read.

Yes, I wrote specification. Because that is how BDD views what TDD basically calls a test suite. The suite specifies the behaviour of a `class´. (That’s why some BDD frameworks draw on spec, like RSpec.)

As you can see in the short example above, you have to give the SUT in the Ensure() declaration too. If you don’t, Cgreen will get confused about which style you are using and your source won’t compile.

1.2.  Contexts and Before and After

The complete specification of the behaviour of a SUT might become long and require various forms of setup. When using TDD style you would probably break this up into multiple suites having their own setup() and teardown().

With BDD style we could consider the suite as a behaviour specification for our SUT in a particular context. E.g.

#include <cgreen/cgreen.h>

Describe(shopping_basket_for_returning_customer);

Customer *customer;

BeforeEach(shopping_basket_for_returning_customer){
  customer = create_test_customer();
  login(customer);
}

AfterEach(shopping_basket_for_returning_customer) {
  logout(customer);
  destroy_customer(customer);
}

Ensure(shopping_basket_for_returning_customer, can_use_discounts) {
  ...
}

The 'context' would then be shopping_basket_for_returning_customer, with the SUT being the shopping basket 'class'.

We have added two 'functions' which are exactly what they say they are. Before each 'test' (or behaviour specification) the customer record will always be create and the customer logged in, exactly like we could do with the setUp() function in TDD style. In the same manner, after each 'test' the customer will be logged out and the record destroyed.

I’ve been holding back on running Cgreen with this example because you need to write all three of the new 'functions' (of course you can see that they are CPP macros, right?), to make that work.

And there is one more thing. To run this using the same kind of main program that we saw earlier, we need must add the SUT when we add the test to suite:


TestSuite *shopping_basket_tests()
{
  TestSuite *suite = create_test_suite();
  add_test_with_context(suite, shopping_basket_for_returning_customer, can_use_discounts);
  return suite;
}

Note that you don’t need to (and shouldn’t) add any setup or teardown to the suite. That’s already taken care of by the BeforeEach() and AfterEach() definitions.

Now we are ready to run the tests by compiling and linking as always.

1.3.  Changing Style

If you have some TDD style Cgreen test suites, it is quite easy to change them over to BDD style. Here are the steps required

  • Add Describe(SUT);

  • Turn your current setup function into a BeforeEach() definition by changing is signature to match the macro. If you don’t have any setup function you need to define an empty BeforeEach().

  • Ditto for AfterEach().

  • Remove any set_setup() and set_teardown()

  • Add the SUT to each Ensure() as the first parameter

  • Change the call to add the tests to add_test_with_context()

Done.

It is good that this is a simple process, because you can change over from TDD style to BDD style in small steps. You can convert one source file at a time, by just following the recipe above. Everything will still work as before but your tests and code will likely improve.

And once you have changed style you can fully benefit from the automatic discovery of tests as described in Automatic Test Discovery.