TDD vs BDD
The main focus of this post is to describe the unit test class structures I use, which are a mixture between TDD (Test Driven Development), and BDD (Behaviour Driven Development) patterns. The difference between TDD and BDD is quite subtle, but once realised it is quite profound. Matt Wynne tackles the subject in a TDD vs BDD blog post describing TDD as very similar to BDD, except that BDD had a much more business, or customer centric focus, while TDD was more system oriented. In Matt's book - The Cucumber Book, he describes unit tests as focusing on "building the system right", whilst acceptance tests focus on "building the right system", and we can draw a similar comparison between TDD and BDD. Since we can mock our to dependencies to test complex business logic, we can write our BDD style acceptance tests as unit test classes.
Both TDD and BDD are about -
- defining your specification first, i.e. the test
- writing enough code to allow the test to fail meaningfully
- writing the functional code to deliver the working solution for the test
- refactoring the solution to improve the code, i.e. DRY it up (DRY - Don't Repeat Yourself)
My main focus on TDD and BDD is related to the patterns of the test code.
Arrange Act Assert
The pattern typically used in TDD unit tests is called the AAA pattern or "Arrange Act Assert", where basically you -
- Arrange the state of the test item
- Perform an action on the test item
- Assert the result of the action
I use the AAA pattern for performing simple unit tests on self contained classes, which I can easily supply inputs, execute a test, and then verify the results.
The structure of these tests is very simple, typically a test method for each test, and perform the Arrange, Act, Assert functionality within the single test method. See the example below related to the "happy hour" example from the first post I published on testing
The test example below is simply checking that the LookupPrice method returns the expected result for the "Little Creatures Pale Ale" beer.
Gherkin is a language for writing acceptance tests such that a non technical user can understand the specification, and also allows a developer to interpret what system tests will verify that the logic meets the test expectations.
Gherkin is structured as -
- Given some pre condition
- When a particular action is performed
- Then an expected result should be obtained
As you can see, the pattern of the test is very similar to AAA, but subtly, the test is written in relation to the expected behaviour of the system from a business logic perspective, rather than the technical execution of a single class which is being unit tested.
From this perspective, I typically use BDD styled tests for testing business logic defined as user stories in an agile project, but for simple unit test cases on internal classes, I write AAA styled tests.
In the examples shown below, I have a base class called SpecificationContext that executes the Given and When methods in the test initialise. Each test class executes the Then methods as each individual test.
I derive from the SpecificationContext class to provide a DrinkOrderContext class which creates a context that I can perform a number of different BDD styled tests on.
My test classes are named according to the Given and When aspect of the test, and the test methods represent the Then component of the test, such that the results of running the tests show the class name in one result column, and the test in the next column. If my tests had multiple expectations i.e. Then blah And blah, then each expectation would be another test Then. Each test is then run independently, so there are no tests dependent on another test having been executed.
Example results are shown below.
This was just a brief introduction to the class structure of my tests so that you understand the pattern on the tests that I will be discussing in future posts.
Hopefully the discussion about TDD/BDD patterns gave you something to think about in terms of patterns for test cases. From a practical perspective, I use the Gherkin styled pattern for defining acceptance tests so that I can easily verify that I have captured a customer's expected system behaviours within my test suites, which gives me confidence that I am delivering the expected solution, as well as "safe" environment to refactor the solution to improve code reuse, or optimise for performance down the track.