xUnit.BDDExtensions is a little framework build on top of xUnit which enables a BDD style of testing with xUnit. Besides an emphasis on a
“test case class per fixture” organization scheme for tests, AAA (Arrange, Act and Assert) style of writing tests and left to right
assertions, this framework also provides Rhino.Mocks integration out of the box. By hiding the mechanics of Rhino.Mocks (record and replay
model, mocks vs. stubs) behind the scenes, xUnit.BDDExtensions also helps on writing cleaner, easier to understand and less brittle tests
xUnit.BDDExtensions is based on JP Boodhoos BDD extensions for MBUnit used in his “Nothing but .NET” bootcamps.
Enough of the talking, let’s look at some code
This is actual code of the xUnit.BDDExtensions trunk. The
SpecificationTestCommand class serves as a kind of adapter inside
xUnit. It enables the test class to have methods that are run before and after the actual test method is executed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Notice several things:
- It expects the instance to implement
- It calls the
InitializeSpecification()method on it
- Passes the execution to the inner command (in
- and finally cleans up the specification by calling
So how can a completely isolated happy path test for this look like?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
Notice several things:
- In the
EstablishContext()method the whole context for the test is created. This includes creating most of the dependencies with Rhino.Mocks through
Dependeny()and the necessary configuration of their behavior. This is done in order to quickly get from an interaction based style of testing to a state based style of testing. In AAA terms this method implements the Arrange part.
CreateSut()method is executed after
EstablishContext()and creates the actual system under test.
Because()method implements the actual behavior under test. In AAA terms this is the Act part. In the current example this meant executing the test command with an instance implementing the expected interface.
- Each method marked with the
ObservationAttributecontains a single observation which should be fulfilled when the test has been executed. In AAA terms every Observation is an Assert.
That’s basically it. Pretty straight forward imho. If I managed to make you at least a bit curious about this style of testing, you can grab the source with any git client from: http://github.com/bjro/xunitbddextensions