|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
MbUnit was previously named GUnit. It has been renamed to avoid name clashing with another project. IntroductionUnit testing is a great tool for ensuring an application quality and frameworks like NUnit [1] or csUnit [2] 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 Recently, Marc Clifton has formalized more than twenty unit test patterns in [3]. 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 In the following, it is assumed that the reader has basic knownledge of unit tests (NUnit, csUnit, JUnit).. A simple exampleIn 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 PatternLet 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 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 Defining the TestFixture attribute in MbUnitAs 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();
// setup
OptionalMethodRun setup = new
OptionalMethodRun(typeof(SetUpAttribute),false);
runs.Runs.Add( setup );
// tests
MethodRun test = new
MethodRun(typeof(TestPatternAttribute),true,true);
runs.Runs.Add(test);
// tear down
OptionalMethodRun tearDown = new
OptionalMethodRun(typeof(TearDownAttribute),false);
runs.Runs.Add(tearDown);
return runs;
}
}
where
Tagging a class and scanning the test classWhen you provide a test assembly to the framework, it will scan for test class tagged with Once the fixture is extracted, the framework calls 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.
Method decoratorsIt is also possible to add "test decorator" like ExpectedException, which checks that an exeception is thrown: ...
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void TestThrow()
{
throw new ArgumentNullException();
}
Other supported decorators are:
Execution SplittingIn order to have fully separated test, we create and store all the execution path and attach it to some GUI, usually a
The execution pipes are called Framework, buillt-in fixturesMbUnit already comes with a few usefull fixtures, such as the Simple Test Fixture. Fixtures classes must derive from the TestFixture
This fixture implements the Simple Test Pattern: [TestFixture]
public class MyTest
{
[SetUp]
public void SetUp()
{
// set up the fixture
}
[Test]
public void Test1()
{
// do some test
}
[Test]
public void Test2()
{
// another test
}
[TearDown]
public void TearDown()
{
// clean up
}
}
TypeFixture
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 [TypeFixture(typeof(IList),"IList test")]
public class TypeFixtureAttributeTest
{
[Provider(typeof(ArrayList))]
public ArrayList ProvideArrayList()
{
return new ArrayList();
}
[Provider(typeof(ArrayList))]
public ArrayList ProvideFilledArrayList()
{
ArrayList list = new ArrayList();
list.Add("hello");
list.Add("world");
return list;
}
[Test]
public void AddElement(IList list)
{
int count = list.Count;
list.Add(null);
Assert.AreEqual(list.Count,count+1);
}
}
EnumerationFixture
This fixture implements the testing of an [EnumerationFixture]
public class DictionaryEnumerationFixtureAttributeAttributeTest
{
private Random rnd = new Random();
private int count = 100;
[DataProvider(typeof(Hashtable))]
public Hashtable HashtableData()
{
Hashtable list = new Hashtable();
for(int i=0;i<count;++i)
list.Add(rnd.Next(),rnd.Next());
return list;
}
[Provider(typeof(Hashtable))]
public Hashtable HashtableProvider(IDictionary source)
{
Hashtable list = new Hashtable();
foreach(DictionaryEntry de in source)
{
list.Add(de.Key,de.Value);
}
return list;
}
[Provider(typeof(SortedList))]
public SortedList SortedListProvider(IDictionary source)
{
SortedList list = new SortedList();
foreach(DictionaryEntry de in source)
{
list.Add(de.Key,de.Value);
}
return list;
}
}
Examples and demoHere are some details about the projects inclosed in the demo solution:
Conclusions and further workMbUnit 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. History
References
|
||||||||||||||||||||||