LeapingGorilla.Testing is an attribute based framework for BDD style Given/When/Then unit testing without the ceremony.
The LeapingGorilla.Testing is now available on NuGet. Get it using:
PM> install-package LeapingGorilla.Testing
or if you prefer XUnit:
PM> install-package LeapingGorilla.Testing.XUnit
We at Leaping Gorilla strive to remove as much friction as possible from our testing methodology. To that end we wanted a drop dead simple way to create unit tests that adhered to a few core principles:
- Must support constructor-based dependency injection
- Must have the ability to automatically mock any dependencies we wish to use with our item under test
- Must have the ability to override automatic mocking should the need arise
- Must support a clean syntax for stubbing method calls on our dependencies
- Must have a clean BDD style Given/When/Then flow
From these needs LeapingGorilla.Testing was born.
LeapingGorilla.Testing builds on the shoulders of giants. We use NUnit as our core testing framework, NSubstitute performs mocking duties and Fast-member provides quick reflective access to members on our classes. We also have a version which builds on XUnit rather than NUnit should that be your favoured framework.
Enough of the introductions, lets look at how it works.
public class WhenTestingStubbing : WhenTestingTheBehaviourOf
{
[ItemUnderTest]
public ClassRaisingAnEvent ClassRaisingEvent { get; set; }
[Dependency]
public IMockEventRaiser EventRaiser { get; set; }
private string _severeResponse;
private string _severeReturn;
[Given]
protected void TheEventRaiserHasSevereResponse()
{
_severeResponse = "This is a severe response";
EventRaiser.RaiseEvent(true).Returns(_severeResponse);
}
[When]
protected void TheEventRaiserRaisesASevereEvent()
{
_severeReturn = ClassRaisingEvent.DoSomethingWithTheEventRaiser(true);
}
[Then]
public void SevereReturnShouldMatchResponse()
{
Assert.That(_severeReturn, Is.EqualTo(_severeResponse));
}
[Then]
public void EventRaiserShouldBeCalled()
{
EventRaiser.Received(1).RaiseEvent(Arg.Any<bool>());
}
}
Here you can see the attribute led style that LeapingGorilla.Testing uses to make testing painless. We start with the concept of an ItemUnderTest
. This is the concrete instance that the framework will create for us. This concrete instance has dependencies injected via the constructor - in this case an IMockEventRaiser
. We mark a property of this with a DependencyAttribute
and we're good to go.
LeapingGorilla.Testing starts by locating all of our Dependencies, creating a mock of each and loading them into the test class. Next it finds the item under test, finds the constructor that best matches our dependencies and then creates an instance of the item under test passing the dependencies into the constructor and loads it into the test class.
From here we look for any methods marked with a GivenAttribute
. You can have as many Given methods as you want (zero, one or more). LeapingGorilla.Testing will find and execute each in turn. The order it will do so is undefined so if you need to be specific on the order that we call them use the optional Order property like:
[Given(Order = 1)]
You should use your Given
methods to setup your stubbing in dependencies. We leverage NSubstitute for this so take a look at the NSubstitute website. With our given methods executed the framework then finds your optional When
method. You may have zero or one method marked with a WhenAttribute
. If one is found it will be called and at this point we hand over to the NUnit framework to assert each of yor test cases.
NUnit will find all public methods marked with a ThenAttribute
and run each of them as an individual test. It's best practice to avoid modifying any state in your Then
tests - you can't guarantee the order they will run in so it's easy to trip yourself up.
- Create a new test class inheriting from
WhenTestingTheBehaviourOf
- Add a property to the class you want to test, mark it with an
ItemUnderTest
attribute - If your item under test has any dependencies to inject in the constructor, add a property for each with a
Dependency
attribute. - If you need to do any test setup (stubbing dependency methods, preparing input parameters or expected output parameters) create a method to do so and mark it with a
Given
attribute. To make life easier you can split your setup into multipleGiven
methods for readability. - If your test needs to call any functionality on your item under test create a method to do so and mark it with a
When
attribute. - Create as many public void methods as necessary to assert that your item under test has performed as expected. Mark each with a
Then
attribute and add whatAssert
statements you need.
A: Override the CreateManualDependencies
method and assign them from there
A: Mark it with a Mock
attribute
A: Convention. At Leaping Gorilla we stick to the rule that each test class tests a single behaviour. If a behaviour can't be expressed as a single "When I X" then we take it as a sign that our code probably needs refactoring.
A: Use the optional Order
property at the point of decoration like:
[Given(Order=2)]
A: The short answer is: You can't. The longer answer is: you can override the CreateManualDependencies
method and substitute your own mock object there but we cannot generate an automatic mock. This is down to the nature of the .Net framework and short of using an expensive tool like TypeMock or JustMock itisn't going to change. Take it instead as an opportunity to do some glorious refactoring to break that concrete dependency into an interface.
A: Make sure that your method returns Task, not void and it will Just Work (tm) like:
[When]
public async Task SomethingAsyncHappens()
{
_result = await MyAsyncThing();
}
A: Fork and submit a pull request! For your pull request to be considered it should include tests as well as functional code.
A: LeapingGorilla.Testing is made available under the Apache 2.0 License. You are free to use the software in any way you choose as long as you adhere to the license.
A: We are open to talk with you or your business! Drop us a line via our contact form.