Separate Action from Assertion in Unit Tests
- by DigitalMoss
Setup
Many years ago I took to a style of unit testing that I have come to like a lot. In short, it uses a base class to separate out the Arrangement, Action and Assertion of the test into separate method calls. You do this by defining method calls in [Setup]/[TestInitialize] that will be called before each test run.
[Setup]
public void Setup()
{
before_each(); //arrangement
because(); //action
}
This base class usually includes the [TearDown] call as well for when you are using this setup for Integration tests.
[TearDown]
public void Cleanup()
{
after_each();
}
This often breaks out into a structure where the test classes inherit from a series of Given classes that put together the setup (i.e. GivenFoo : GivenBar : WhenDoingBazz) with the Assertions being one line tests with a descriptive name of what they are covering
[Test]
public void ThenBuzzSouldBeTrue()
{
Assert.IsTrue(result.Buzz);
}
The Problem
There are very few tests that wrap around a single action so you end up with lots of classes so recently I have taken to defining the action in a series of methods within the test class itself:
[Test]
public void ThenBuzzSouldBeTrue()
{
because_an_action_was_taken();
Assert.IsTrue(result.Buzz);
}
private void because_an_action_was_taken()
{
//perform action here
}
This results in several "action" methods within the test class but allows grouping of similar tests (i.e. class == WhenTestingDifferentWaysToSetBuzz)
The Question
Does someone else have a better way of separating out the three 'A's of testing? Readability of tests is important to me so I would prefer that, when a test fails, that the very naming structure of the tests communicate what has failed. If someone can read the Inheritance structure of the tests and have a good idea why the test might be failing then I feel it adds a lot of value to the tests (i.e. GivenClient : GivenUser : WhenModifyingUserPermissions : ThenReadAccessShouldBeTrue).
I am aware of Acceptance Testing but this is more on a Unit (or series of units) level with boundary layers mocked.
EDIT : My question is asking if there is an event or other method for executing a block of code before individual tests (something that could be applied to specific sets of tests without it being applied to all tests within a class like [Setup] currently does. Barring the existence of this event, which I am fairly certain doesn't exist, is there another method for accomplishing the same thing?
Using [Setup] for every case presents a problem either way you go. Something like [Action("Category")] (a setup method that applied to specific tests within the class) would be nice but I can't find any way of doing this.