Reputation: 16713
Based on some light reading about BDD, I came to the conclusion that unit tests are good tools for testing some granular part of your application, while BDD are higher level, where you are able to exercise feature workflows.
Some of the items I would consider candidates for unit tests: sorting algorithms, state reducers, geometric calculations, etc...
Items I would consider candidates for BDD would be feature workflows: adding an item to a cart, logging in, searching the contents of a site to find course material, etc...
I was asked by a client to write a sorting algorithm, and normally I would have just written a unit test like:
public class SorterTest
{
[TestMethod]
public void TestSort()
{
var numbers = new List<int>() { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
var expected = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var sorter = new Sorter()
{
Input = numbers
};
var sorted = sorter.Sort();
CollectionAssert.AreEqual(expected, sorted.ToList());
}
}
However, the client asked for a BDD test, so I came up with the following:
Feature: Sort
In order to to ensure sorting of integers
I want to be able to sort a collection of integers
Scenario Outline: Perform a sort
Given I have these integers: '<input>'
When I sort them
Then the result should be '<expected>'
Examples:
| input | expected |
| 9,8,7,6,5,4,3,2,1 | 1,2,3,4,5,6,7,8,9 |
To make my Sorter
object testable for BDD, I had to alter it:
private Sorter sorter = new Sorter();
[Given(@"^I have the following integers: '(.*)'$")]
public void GivenIHaveTheFollowingIntegers(string numbers)
{
var inputs = numbers.Split(',')
.Select(s => Convert.ToInt32(s.Trim()))
.ToList();
sorter.Input = inputs;
}
Note for setting up the test with Given
, I had to add an Input
property to Sorter
tp prepare for the sort. The downside is that in application code, if I want my sorter to perform a sort, I will always need to set this property prior to performing the sort:
sorter.Input = intCollection;
var result = sorter.sort();
I'd rather just have:
var result = sorter.sort(intCollection);
Is BDD appropriate for this sort of test? If so, am I doing it right? Adding the Input
property feels wrong, should I be doing it some other way?
If not appropriate, how does one go about drawing the line between BDD and unit tests? There is an existing SO post, but the answers reference a book. It would be nice to get some better guidance.
Upvotes: 7
Views: 7183
Reputation: 532
Firstly, my experience is that BDD-thinking can sometimes be helpful when testing a unit.
Secondly, I would argue that the "Given" keyword is being misused. Could you ask your client to rewrite their scenario as:
Scenario Outline: Perform a sort
When I sort these integers: '<input>'
Then the result should be '<expected>'
I've found that the correct use of Given is for objects that have to exist in the system under test. In your example it is being used for something that exists in the user's head: implementing that in code is bound to be unnatural.
Thirdly, if I had to implement that "Given" clause, I would store the list of integers within the test environment, rather than trying to insert them into the application immediately. Then the "When" step can retrieve them from the test environment and use them where the code needs them.
Upvotes: 1
Reputation: 4592
Choosing between both styles
Choosing between the unit test (TDD) approach and the BDD approach boils down to preference. If the customer asks for BDD, provide BDD. If the team is more comfortable to TDD, use TDD.
Mixing both approaches
The choice is not exclusive. I have experience with mixing both approaches. To answer the question where to draw a line between both approaches the Agile Testing Quadrants are quite helpful:
Drawing a line
I found that the unit test (TDD) approach was more helpful for the technology facing tests. The BDD approach was more helpful for the business facing tests.
Details about this observation
It is more natural to map business requirements to BDD style tests. To test business requirements with some tactile business value, it usually requires the integration of multiple classes. In my experience those BDD style tests were usually integration tests and had the characteristics of functional tests and user acceptance tests.
On the other side the TDD tests were written by programmers for programmers. Many programmers are more comfortable or have more experience with the unit test (TDD) approach. These tests usually tested classes in isolation and with an emphasize on edge cases and technical aspects of the system.
Your provided example is quite an exception because it maps a business case in a single class. In this case both approaches are OK.
Upvotes: 13
Reputation: 468
I would have written a unit test.
You mentionned
Some of the items I would consider candidates for unit tests: sorting algorithms, state reducers, geometric calculations, etc...
Items I would consider candidates for BDD would be feature workflows: adding an item to a cart, logging in, searching the contents of a site to find course material, etc...
and I agree with that. Behavior Driven test are good at "speccing" quickly and making sure that the application behaves properly, and does what it is supposed to. You could take this definition and say that you are making sure that your sort works, but the key (IMO) is that you are not testing how your program works, but how an algorithm works, a very specific element of the program. If you look at how you built the test, you see that you are trying to mimic a unit test: you throw a bunch of input, and you compare with the output you are trying to get.
A BDD test aims to test a feature, as scenarios. For instance, if you had a program that organizes phone numbers from a file, sorting would be a part of the process, but you don't cover "sorting" by itself, you test the general behavior of the program (if you get the expected file resulting from executing the application). You setup the test, execute it, verify the result.
You should also write test before you write the code, and I agree with @Theo Lenndoff, having the input as a property is weird and very counter intuitive. (You mentionned it too).
Upvotes: 4