Click here to Skip to main content
Email Password   helpLost your password?

MbUnit was previously named GUnit. It has been renamed to avoid name clashing with another project.

Introduction

Unit 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 SetUp, Test, TearDown actions. 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 [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 TypeFixture which 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.

Test Pattern

In the above example, we call the TestFixture class a TestFixturePattern, SetUp and TearDown are NonTestPattern tags for mehods that are not considered as tests. Test is a TestPattern. A TestFixturePattern must 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();
            
          // 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 class

When you provide a test assembly to the framework, it will scan for test class tagged with TestFixtureAttribute derived attributes. In this case, we wrote one tagged with TestFixture.

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.

Fixture

Method decorators

It 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 Splitting

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 TreeNode for example, which makes it very easy to launch separately, or to launch all tests in separate threads, etc...

Fixture

The execution pipes are called RunPipe and are composed of a sequence of IRunInvoker instances.

Framework, buillt-in fixtures

MbUnit already comes with a few usefull fixtures, such as the Simple Test Fixture. Fixtures classes must derive from the TestFixturePatternAttribute class. Execution path diagrams are automatically generated by the framework using the QuickGraph [4] and Graphviz [5].

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 Provider attribute must return an initialized object that is assignable with the tested type. This object is then feeded to the test methods:

[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 IEnumerable / IEnumerator pair. The DataProvider tagged 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 CopyToProvider methods that must create an instance of the tested IEnumerable instance and populate with the feeded data. The rest of the testing is done by the framework:

[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 demo

Here are some details about the projects inclosed in the demo solution:

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.

History

References

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralProblem with Invoke() method.
amit_lole
21:20 13 Mar '07  
I am trying to call the DLL dynamically.
in my code one of the statement is as follows:
string strResult = (string)mi.Invoke(null, parameterValues);

parameterValues is a object[] type parameter. It contains two values in the form of string "23/2/2005 1:12:00" & "100"

This statement Gives the following error
"Parameter count mismatch"

my Dll method is as follows:

public static string BRating(string str1, string str2)
{
}
Where is the error? I am not getting.
Please any one can help me to solve this problem.
Generaltypefixture with invalid number of parameters
foris.gabor@stud.u-szeged.hu
6:58 15 Nov '04  
Hello,

I have downloaded the sample classes from http://www.thecodeproject.com/csharp/JdhCompositeUnitTesting.asp to test the typefixture, yet when I try to run the tests in mbunit GUI, I get the following error message:

>>>>>
Message: Parameter count mismatch.

Type: System.Reflection.TargetParameterCountException
Source: mscorlib
TargetSite: System.Object Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
HelpLink: null
Stack:   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at MbUnit.Core.TypeHelper.Invoke(MethodInfo method, Object o, IList args) in C:\svnhome\trunk\MbUnit\MbUnit.Core\TypeHelper.cs:line 574
   at MbUnit.Core.Invokers.MethodRunInvoker.Execute(Object o, IList args) in C:\svnhome\trunk\MbUnit\MbUnit.Core\Invokers\MethodRunInvoker.cs:line 74
   at MbUnit.Core.RunPipeStarter.Run(Object fixture) in C:\svnhome\trunk\MbUnit\MbUnit.Core\RunPipeStarter.cs:line 128
<<<<<

Does anybody have any idea why it does not work?Frown



Regards,
Gabor

GeneralGUnit changed named to MbUnit and moved of site
Jonathan de Halleux
7:16 24 Mar '04  
Moved to http://mbunit.tigris.org[^]

Jonathan de Halleux.

www.dotnetwiki.org

GUnit

GeneralGUnit at Tigris
Jonathan de Halleux
21:32 15 Mar '04  
The new home page of GUnit is now http://gunit.tigris.org[^]


Jonathan de Halleux.

www.dotnetwiki.org

GUnit

GeneralProblems with 1.2
Stephen Johns
10:57 2 Mar '04  
First, let me say that I am very excited by this project. I think this approach to testing is excellent.

I downloaded and built the latest distribution.
Using the tutorials on wiki, I wrote my first test class.

The problem I am having is that I need to use an assembly someone else wrote. Foo.dll. When I first tried to add Foo.dll, GUnit said "Can't find FooDll.dll", I found the lost FooDll.dll, put it where GUnit could find it, then tried to add Foo again. It worked - shows up in the GUI and everything. Then I tried to add my .dll (that uses Foo.dll). GUnit throws FileNotFoundException saying that Foo.dll or one of its dependencies can't be found.

Any ideas?

Using:
.NET Framework 1.1.4322
Microsoft Visual C# .NET 69461-270-0000007-18487
GeneralRe: Problems with 1.2
Stephen Johns
11:05 2 Mar '04  
More input. Copying Foo.dll and FooDll.dll into the GUnit.GUI/bin/Debug directory allows my DLL to load.

My tests run.

Question: Is there anyway to save a configuration? My "File" menu does not contain any MenuItems.

GeneralRe: Problems with 1.2
Jonathan de Halleux
11:25 2 Mar '04  
Stephen Johns wrote:
Is there anyway to save a configuration? My "File" menu does not contain any MenuItems.

Hi, the GUI is still very beta. And yes, it is annoying to not being able to store the configuration.

I'm adding that to my todo list Smile

Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Problems with 1.2
Jonathan de Halleux
11:26 2 Mar '04  
Stephen Johns wrote:
First, let me say that I am very excited by this project. I think this approach to testing is excellent.

Smile


I will be looking at the problem of Dll loading as soon as possible. One item more on the todolist.

Jonathan de Halleux.

www.dotnetwiki.org

Generalv1.2 is out
Jonathan de Halleux
15:39 24 Feb '04  
Brand new GUI available + NAnt task!!!

Jonathan de Halleux.

www.dotnetwiki.org

GeneralComment your votes
Jonathan de Halleux
22:23 17 Feb '04  
Please if you don't like the package or you find some severe design fault, you can vote accordingly but be constructive and feedback.


Jonathan de Halleux.

www.dotnetwiki.org

GeneralVC++ 6.0
Jose Toledo
22:18 16 Feb '04  
Great job!

I work with VC++ 6.0 Can I use GUnit?

Jose
GeneralRe: VC++ 6.0
Jonathan de Halleux
0:57 17 Feb '04  
Impossible! GUnit is a .Net application,it does not work with C++. You need to upgrade to VS.Net...

Cheers,Jonathan

Jonathan de Halleux.

www.dotnetwiki.org

GeneralNice
Giles
1:44 15 Feb '04  
More food for thought. Thanks.

So now we know where you get all these ideas - morphine. Should have guessed. Big Grin






"Je pense, donc je mange." - Rene Descartes 1689 - Just before his mother put his tea on the table.

Shameless Plug - Distributed Database Transactions in .NET using COM+
GeneralRe: Nice
Jonathan de Halleux
3:37 15 Feb '04  
Actually, hospital is a nice place to spit out code:

- food comes at constant time, it comes at bed, you don't have move away from the computer,
- you can sleep in front of your computer, when you wake up it's still there, ready to work,
- morphine makes you sleepy but releives pains. The best is that while you concentrate on coding, your brain does not focus on the pain.
- you have nothing else to do!

Don't hesitate to feedback on GUnitSmile

Cheers,
JOnathan

Jonathan de Halleux.

www.dotnetwiki.org

GeneralIn general
David Gallagher
6:44 11 Feb '04  
I have read all your articles , and find them to be an excellent source of information.
I've wondered where you get the time to do all this .
Now I know.
Hospitalisation.
I'll be poking my appendix all week in the hope that it gives out and I'll find time to get on with my personal projects.

WTF

.netter
GeneralRe: In general
Jonathan de Halleux
7:54 11 Feb '04  
Thanks,

Actually, I was snowboarding and I fell from a roof onto a steal bar (hidden in the snow). Luckily, it has hit only my knee and not my back. If it had hit my back, I would be in a wheel chair spitting out an article every two days Smile



Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: In general
Garth J Lancaster
11:29 11 Feb '04  
Jonathan de Halleux wrote:
was snowboarding and I fell from a roof onto a steal bar (hidden in the snow)

... are you contending the Darwin awards ?? I just dont get 'snowboarding' and 'roof' in the same sentence

At least you're relatively ok, THIS TIME - please take more care Jonathan, we want you around a lot longer yet - how will the rest of us 'challenged' ones learn if you stop producing articles ?

'G'
GeneralRe: In general
Jonathan de Halleux
1:34 12 Feb '04  
Garth J Lancaster wrote:
... are you contending the Darwin awards ?? I just dont get 'snowboarding' and 'roof' in the same sentence

Not at all, it was a stormy day and we went too much out of track. Did I tell you the story when I smashed my head on a rock while kayaking ? Smile


Garth J Lancaster wrote:
if you stop producing articles ?

Smile I suppose my article production will lower when I stop working for University Smile

Jonathan de Halleux.

www.dotnetwiki.org

GeneralSomewhat difficult to get started
Pål K Tønder
22:57 10 Feb '04  
I do like the ideas that you present, but I think they would be more easily understood if your download included some examples (I couldn't find it). For the fun of it, the tests could be in your source code, but maybe instead in example projects.

Another thing I would like is some documentation about the GUnit GUI app, because I'm not sure how it's supposed to work

This is minor details, I really like this article
GeneralRe: Somewhat difficult to get started
Jonathan de Halleux
0:40 11 Feb '04  
Pål K Tønder wrote:
I do like the ideas that you present, but I think they would be more easily understood if your download included some examples (I couldn't find it). For the fun of it, the tests could be in your source code, but maybe instead in example projects.

You can check out the GUnit.Tests project which contains illustrations of the test classes.


Pål K Tønder wrote:
Another thing I would like is some documentation about the GUnit GUI app, because I'm not sure how it's supposed to work

The GUI is quite simple: drap and drop and use the Add button to load assemblies containing test classes. Then hit Run to run the tests. The tree on the left contains the tree of tests. If a test failed, click on it to get information about the failure. Smile

Currently, the GUI application sucks: icon do not look nice, etc... It should be improved in the future, or better, GUnit may be integrated in some existing GUI.

Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Somewhat difficult to get started
kwokoek
13:42 17 Feb '04  
While i was able to get this started relatively quickly, i think a "quick start" doc at the root would be useful.

I know the gui is in a primitive state, but i would find some kind of notification that the tests have completed to be useful. I also am not seeing std out show up anywhere (I do see the stack trace on a failure, which is great).

I love the concepts you are presenting, and am looking forward to updates!
GeneralRe: Somewhat difficult to get started
Jonathan de Halleux
22:19 17 Feb '04  

kwokoek wrote:
love the concepts you are presenting, and am looking forward to updates!

kwokoek wrote:
While i was able to get this started relatively quickly, i think a "quick start" doc at the root would be useful.

This makes 1 todo more in my list Smile. In fact, the NDoc is somewhat missing an introductory chapter. Anyway, I have takened a lot of time to comment with examples all the attributes found in the GUnit.Core.Framework and GUnit.Framework.

kwokoek wrote:
but i would find some kind of notification that the tests have completed to be useful.

another todo in my list. What kind of notification are you thinking about ? a "dingdong", email. Actually, I need to rework/improve the way results are stored. I think an implementation with listeners will be the most powerfull: out-putting results to database, etc...

kwokoek wrote:
I also am not seeing std out show up anywhere (I do see the stack trace on a failure, which is great).

A third todo in my list. In fact, I do not redirect the output. I will add that feature to the next release.

kwokoek wrote:
I love the concepts you are presenting, and am looking forward to updates!

I've just finished a NAnt task for gunit and I will trying to get an VS Add-In working.


Jonathan de Halleux.

www.dotnetwiki.org

GeneralRe: Somewhat difficult to get started
Jonathan de Halleux
6:23 24 Feb '04  
I have started to write a few tutorials on my wiki-web about GUnit. You can check it out at http://www.dotnetwiki.org Smile

Jonathan de Halleux.

www.dotnetwiki.org

GeneralG-Unit
mystro_AKA_kokie
11:43 10 Feb '04  
is that a play on the hihop group?Smile


It's a sh*tty world. Take advantage of whomever,whenever,whereever. And oh.. becarefull what you say to me,am too sensitive.Or i might just show up at your house.i retract the latter,am trying to be a better person.

GeneralRe: G-Unit
Jonathan de Halleux
12:19 10 Feb '04  
Is it a hiphop group? I'm a bit out of sync with hiphop right now... Smile

Jonathan de Halleux.

www.dotnetwiki.org


Last Updated 16 Apr 2004 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010