MbUnit was previously named GUnit. It has been renamed to avoid name clashing with another project.
Unit testing is a great tool for ensuring an application quality and frameworks like NUnit  or csUnit  have made it very simple to implement. However, as the number of tests begins to grow, the need for more functionalities begin to show up. The above frameworks are based on the Simple Test Pattern which is basically the sequence of
TearDownactions. Although highly generic, this solution lets a lot of work to be done by the test writer. Sadely, there is no easy way to derive and include a new "fixture" type in those frameworks.
Recently, Marc Clifton has formalized more than twenty unit test patterns in . In a perfect world, each of these patterns would have a "specialized" fixture: testing a collection should not require rewritting the test class for each collection instance, this is what I thought after reading Marc's article, the next thought was "let's do it".
While enjoying my stay in hospital for surgery, I spent the time writing a new generative test unit framework called MbUnit. The objective of the framework is give to the end-users the "high order" test fixtures and to the develpers the tools to build new custom fixtures without modifying the Core. To illustrate that, MbUnit implements the Simple Test Pattern and provides new fixture types, like the usefull
TypeFixturewhich applies tests to a particular type instance. It must emphasize that MbUnit is still a prototype, was written under the influence of morphine and other pain-killer substance, and is published on the CodeProject to get constructive feedback from CPians and specially from members of the AUT project.
In the following, it is assumed that the reader has basic knownledge of unit tests (NUnit, csUnit, JUnit)..
A simple example
In this example, we show the motivation for MbUnit and the key features about it. While developping the example, we show what kind of data-structure is needed and how the core was be built.
Simple Test Pattern
Let us consider the Simple Test Pattern which is implemented by most test unit framework available. This is the classic way of writing unit test as described in the figure below. A
TestFixture attribute tags the test class, one
SetUp method, tests are done in the
Test tagged method and clean up is performed in
TearDown tagged method. This is illustrated in the left of the figure.
The figure already illustrates one of the key idea of MbUnit: Fixture class should be definable at runtime by creating an execution pipe, using basic building blocks (SetUpAttribute, TestAttribute, etc...) provided by the framework.
In the above example, we call the
NonTestPatterntags for mehods that are not considered as tests.
TestFixturePatternmust be able to describe itself at runtime and return it's execution path.
Defining the TestFixture attribute in MbUnit
As mentionned in the introduction, MbUnit provides basic building blocks that a developer can use to build complex fixtures. For example, the Simple Test pattern is implemented as follows in MbUnit (source first, comment below)
public class TestFixtureAttribute : TestFixturePatternAttribute
public override IRun GetRun()
SequenceRun runs = new SequenceRun();
OptionalMethodRun setup = new
runs.Runs.Add( setup );
MethodRun test = new
OptionalMethodRun tearDown = new
TestFixturePatternAttributeis the abstract base class for all new fixture attribute in MbUnit,
GetRunmethod is called by the MbUnit core to know what is the execution path of the fixture. The fixture can use built-in basic attributes to build it's execution path.
IRuninstance can represent the call to a method, or to a sequence of methods, etc...
SequenceRunis a sequence of
IRuninstance that wraps a call to a method tagged by a predefined attribute.
OptionalMethodRun is inherited from
MethodRunand describes optional methods.
Tagging a class and scanning the test class
When you provide a test assembly to the framework, it will scan for test class tagged with
TestFixtureAttributederived attributes. In this case, we wrote one tagged with
Once the fixture is extracted, the framework calls
GetRun()method and starts to explore the execution path.
The figure below show the different execution routes that are possible in the ClassicTest class. The two test method generate to branch in the execution tree.
It is also possible to add "test decorator" like ExpectedException, which checks that an exeception is thrown:
public void TestThrow()
throw new ArgumentNullException();
Other supported decorators are:
ExceptedException, checks that an exception is thrown,
Repeat, test repeated sequentially,
ThreadedRepeat, test repeated on parralel threads,
Duration, lower and upper execution duration test,
Ignore, ignores the test
In order to have fully separated test, we create and store all the execution path and attach it to some GUI, usually a
TreeView. Each execution path can be attached to a
TreeNodefor example, which makes it very easy to launch separately, or to launch all tests in separate threads, etc...
The execution pipes are called
RunPipeand are composed of a sequence of
Framework, buillt-in fixtures
MbUnit already comes with a few usefull fixtures, such as the Simple Test Fixture. Fixtures classes must derive from the
TestFixturePatternAttributeclass. Execution path diagrams are automatically generated by the framework using the QuickGraph  and Graphviz .
This fixture implements the Simple Test Pattern:
public class MyTest
public void SetUp()
public void Test1()
public void Test2()
public void TearDown()
This fixture applies the test to a particular type. It is highly convinient when you want to write a fixture for an interface and test the interface implementations. The method tagged with
Providerattribute must return an initialized object that is assignable with the tested type. This object is then feeded to the test methods:
public class TypeFixtureAttributeTest
public ArrayList ProvideArrayList()
return new ArrayList();
public ArrayList ProvideFilledArrayList()
ArrayList list = new ArrayList();
public void AddElement(IList list)
int count = list.Count;
This fixture implements the testing of an
DataProvidertagged methods must return an enumerable collection that will be used to populate the test
IEnumerable. This lets you test different scenarios like the empty collection case, null value, duplicate entries, etc... The collection is then feeded to the
CopyToProvidermethods that must create an instance of the tested
IEnumerableinstance and populate with the feeded data. The rest of the testing is done by the framework:
public class DictionaryEnumerationFixtureAttributeAttributeTest
private Random rnd = new Random();
private int count = 100;
public Hashtable HashtableData()
Hashtable list = new Hashtable();
public Hashtable HashtableProvider(IDictionary source)
Hashtable list = new Hashtable();
foreach(DictionaryEntry de in source)
public SortedList SortedListProvider(IDictionary source)
SortedList list = new SortedList();
foreach(DictionaryEntry de in source)
Examples and demo
Here are some details about the projects inclosed in the demo solution:
MbUnit.Corecontains the core of the MbUnit framework. No fixtures are defined here.
MbUnit.Frameworkcontains predefined fixtures discussed above
MbUnit.Testscontains some test classes using the fixtures from
MbUnit.Consis a console demo application
MbUnit.GUI is a GUI application that you can use to load test assemblies. It will show the available tests and run the tests. At the current moment, this application is very basic.
Conclusions and further work
MbUnit is yet another way of looking at Unit testing. I beleive it has idea that should interrested the AUT team: It provides enough flexibility to let developer define their own fixture which makes it very powerful with regards to classic framework. While there is much work to do, (a lot of unit patterns to implement), MbUnit already provides new type of fixtures that ease up the test writer life.
- Changed name to MbUnit,
- Moved to Tigris
- Added colors to the GUI to know if tests failed, run successful,
- Added progress bar, with test count
- Better layout to see exception source.