Project DescriptionA Behavior Driven Design (BDD) library adding a clearer syntax and better organization to unit tests. Currently tested working with NUnit and MSTest.
Quick Start1) Download the pre-compiled assembly and add a reference to it from your
test project.
2) Create a new class deriving from
Behavioral.UnitTest<TTarget> or
Behavioral.UnitTest<TTarget, TReturnType>. The latter is required for testing methods that return a type, ie: are not
void.
3) In the class' constructor, call
GivenThat<TInitializer>(),
When<TAction>() and
Then<TAssertion>(), specifying English-language sentences (in Pascal Case) for the type arguments.
4) Define the classes in part 3, implementing
IInitializer<TTarget>,
IAction<TTarget> and
IAssertion<TTarget>, respectively.
ExampleHere is a very simple example of how to use Behavioral - in conjunction with NUnit - to test the
Add() method of a simple
Calculator class.
CalculatorTests.cs
using Behavioral;
using NUnit;
namespace MyTests
{
[TestFixture]
public class AddingTwoPositiveNumbersShouldGiveCorrectResult : UnitTest<Calculator, int>
{
[Test]
public override void Run()
{
GivenThat<CalculatorIsDefaultConstructed>();
When<TwoNumbersAreAdded>(13, 45);
Then<ResultShouldMatch>(58);
}
}
[TestFixture]
public class AddingNumbersThatCausesOverflowShouldThrowOverflowException : UnitTest<Calculator, int>
{
[Test]
public override void Run()
{
GivenThat<CalculatorIsDefaultConstructed>();
When<TwoNumbersAreAdded>(int.MaxValue, 1);
ThenThrow<OverflowException>();
}
}
}
CalculatorInitializers.cs
public class CalculatorIsDefaultConstructed : IInitializer<Calculator>
{
public void SetUp(ref Calculator calculator)
{
calculator = new Calculator();
}
}
CalculatorActions.cs
public class TwoNumbersAreAdded : IAction<Calculator, int>
{
public TwoNumbersAreAdded(int x, int y)
{
this.x = x;
this.y = y;
}
public int Execute(Calculator calculator)
{
return calculator.Add(this.x, this.y);
}
private int x;
private int y;
}
CalculatorAssertions.cs
public class ResultShouldMatch : IAssertion<Calculator, int>
{
public ResultShouldMatch(int expectedValue)
{
this.expectedValue;
}
public void Verify(Calculator calculator, int returnValue)
{
Assert.AreEqual(this.expectedValue, returnValue);
}
private int expectedValue;
}
So, that's a simple example of how to trivially test the following Calculator implementation:
Calculator.cs
public class Calculator
{
public int Add(int x, int y)
{
checked
{
return x + y;
}
}
}
BackgroundBehavior Driven Development (BDD) is the natural next step after Test Driven Development (TDD). BDD is many different things, but one aspect of BDD is addressed by
Behavioral: unit test organization.
The usual way of organizing unit tests is as follows:
[TestFixture]
public class CalculatorFixture
{
[SetUp]
public void SetUp()
{
this.calculator = new Calculator();
}
[Test]
public void CanAddTwoPositiveNumbers()
{
int result = this.calculator.Add(13, 45);
Assert.AreEqual(58, result);
}
[Test]
public void AdditionOverflowCausesException()
{
Assert.Throws<OverflowException>(() => this.calculator.Add(int.MaxValue, 1));
}
private Calculator calculator;
}
As the tests become more complex and involved, there are two problems with this approach that are addressed by
Behavioral.
- The tests do not promote reuse, neither of the initialization code, the action under test nor the assertions that are made after the fact.
- The tests can become hard to understand and, as the tests in an agile project form a reliable documentation of the code's intent, it is important to keep them simple.