Introduction
With this article, I am demonstrating a certain source code structure for behavior-driven development (BDD) compatible with many testing frameworks.
One advantage of this style is how it integrates with source code viewing tools such as Solution Explorer and ReSharper (R#). Another is that the tests are very easy to read and understand, even for less-technical people.
For my example, I will use Machine Specifications (MSpec) because I prefer that framework's syntax.
Background
This article is intended for people with some familiarity with BDD. Wikipedia's article on the topic is here and the BDD wiki sits here. Another link that some readers may find helpful is the one I have included on MSpec. A tutorial for wiring R# and MSpec together can be found here.
Using the Code
The code is divided into two projects: Banking (the main project) and Banking.Behavior (the test project).
What I am showing here is the source that mirrors a user story: As a\[Role]\I Want\[Feature]\so that\[Benefit]:
Banking.Behavior\As an\account holder\I want\to transfer
money from my savings account\so that\I can get cash easily from an ATM
Typically, a single user story is comprised of many scenarios. Therefore, the source structure mirrors this fact as well: As a\[Role]\I Want\[Feature]\When\[Scenarios]:
Banking.Behavior\As an\account holder\I want\to transfer money
from my savings account\When\I_transfer_an_amount_less_than_my_savings_account_balance.cs
Each scenario has one-to-many assertions, which sit inside the associated scenario file:
using Banking;
using Machine.Specifications;
using NUnit.Framework;
namespace When
{
public class I_transfer_an_amount_less_than_my_savings_account_balance
{
static Account _savings;
static Account _checking;
Because of = () =>
{
_savings = new Account(100);
_checking = new Account(10);
new Bank().Transfer(_savings, _checking, 20);
};
It should_subtract_the_amount_from_my_savings_account_balance = () =>
Assert.That(_savings.Balance, Is.EqualTo(80));
It should_add_the_amount_to_my_checking_account_balance = () =>
Assert.That(_checking.Balance, Is.EqualTo(30));
}
}
The scenario here is I_transfer_an_amount_less_than_my_savings_account_balance
, and the assertions are should_subtract_the_amount_from_my_savings_account_balance
and should_add_the_amount_to_my_checking_account_balance
. Notice that I have placed this class inside the When
namespace. This provides clarity when viewing the source code from a test runner.
I use ReSharper (R#) for my test runner. Here is the view from R#'s 'Unit Test Explorer' with the 'Projects and Namespaces' option:
Here is the view from R#'s Unit Test Sessions with the 'Projects Structure' option:
Here is the view from Solution Explorer:
Note: to run the example project, you will need to include the Machine.Specifications, Machine.Specifications.NUnit, and the NUnit.Framework DLLs yourself. I did not include these DLLs because of potential licensing conflicts between Coderoject.com and those products. The MSpec source can be found here (you have to build it yourself), and the NUnit downloads can be found here.
Points of Interest
This source code structure is portable to many other testing frameworks, such as pure NUnit. In the case of pure NUnit, we would port the It
delegates to [Test]
-decorated methods, the Because
delegates to [SetUp]
-decorated methods, and add the [TestFixture]
attribute to each test class.