Thursday, September 30, 2004

MbUnit now supports setting dependencies between fixtures, similarly to NAnt/MSBuild task dependencies.

How-to

The logic is simple. You can tag a fixture with the DependsOnAttribute to specify a "parent" fixture that should be run before the current fixture. If the parent fixture fails, the current fixture is not run:

[TestFixture]
public class Parent
{...}

[TestFixture]
[DependsOn(typeof(Parent))]
public class Child
{...}

The Child fixture is executed if the Parent fixture executed successfully.

Why do we need dependencies between fixtures ?

Image that you are testing a database. At first, you create a fixture that tests that the connection is correct:

[TestFixture]
public class ConnectionTest
{ ... }

If one of the tests of ConnectionTest fails, then it is likely that all the tests that rely on a database connection will fail and, therefore, should not be executed. Using the DependsOnAttribute, you can specify the dependency of such fixture to the ConnectionFixture.

[TestFixture]
[DependsOn(typeof(Connection))]
public class DALTest
{...}

An example

The following example defines 4 fixture. Child depends on Parent and SickParent, GrandChild depends on Child. Since SickParent has a failed test, Child and GrandChild should not be executed...

[TestFixture]
[CurrentFixture]
public class Parent
{
    [Test]
    public void Success()
    {}
}

[TestFixture]
[CurrentFixture]
public class SickParent
{
    [Test]
    public void Failure()
    {
        throw new Exception("boom");
    }
}

[TestFixture]
[CurrentFixture]
[DependsOn(typeof(Parent))]
[DependsOn(typeof(SickParent))]
public class Child
{
    [Test]
    public void Success()
    {
    }
}

[TestFixture]
[CurrentFixture]
[DependsOn(typeof(Child))]
public class GrandChild
{
    [Test]
    public void Success()
    {}
}

The report result is shown below and one can see that Child and GrandChild fixture have failed without being executed.

posted on Thursday, September 30, 2004 9:00:00 AM UTC  #    Comments [10]
Tracked by:
"universalcard" (online) [Trackback]
"black lable society" (online) [Trackback]
Monday, June 06, 2005 5:24:51 PM UTC
Good stuff. I was wondering if you are thinking about creating a way to declare dependencies at the test case level rather than the test fixture level? I find myself needed this very often where one test case "extends" another and if the first one failed there is really no need to run the second one. Of course I can just explicitly chain these methods where one would call the other one but that is quite unsatisfactory since it runs the same (failing) test more than once and it does not convey the underlying depdendency semantics between two test cases. What do you think?
Sanin Saracevic
Monday, June 06, 2005 5:24:52 PM UTC
Actually I was thinking about adding this to the test level as well. This part is a little bit trickier so I need to think how I can integrate that into the design.
<br>
<br>I will also integrate that on the Assembly level. If you have different test assemblies, you can add dependencies between them...
Jonathan de Halleux
Monday, June 06, 2005 5:24:57 PM UTC
It would be nice if the report inidicated a &quot;fail/skip&quot; status in a different colour (dark red?). This would mean that one can determine which test case needs attention at a glance.
<br>
Dave
Monday, June 06, 2005 5:24:57 PM UTC
Good idea, I'll add a &quot;skipped&quot; status.
Jonathan de Halleux
Monday, June 06, 2005 5:24:57 PM UTC
Peli's Blog
Monday, June 06, 2005 5:24:58 PM UTC
Peli's Blog
Monday, June 06, 2005 5:24:58 PM UTC
Dave,
<br>
<br>I've added &quot;Skip&quot; status for a test.
<br>
Jonathan de Halleux
Monday, June 06, 2005 5:24:58 PM UTC
(This is what I wanted to send you via IM, but we never finished our conversation)
<br>
<br>It's great and I would love for this to propogate to the tests themselves (DependsOnAttribute for tests with the test's name from the current fixture).
<br>
<br>Also, the idea of defining an order of execution is a great idea.
<br>You could create code such as:
<br>
<br>[TestFixture]
<br>public class Tests
<br>{
<br>_ _ [Test(order = 2)]
<br>_ _ public void TestA() { }
<br>
<br>_ _ [Test(order = 1)]
<br>_ _ public void TestB() { }
<br>
<br>_ _ [Test]
<br>_ _ [DependsOn(&quot;TestA&quot;)]
<br>_ _ [DependsOn(&quot;TestD&quot;)]
<br>_ _ public void TestC() { }
<br>
<br>_ _ [Test]
<br>_ _ public void TestD() { }
<br>}
<br>
<br>This would cause TestB to run first, then TestA, then TestD (since TestC depends on its execution) and finally TestC.
<br>Of course, this is a pit ready for you to fall into with circular dependencies (have you thought about that with fixture dependencies?), but it's doable.
<br>
<br>It could be some fun to fiddle with this and see what comes out.
Omer van Kloeten
Monday, June 06, 2005 5:24:58 PM UTC
Hi Omer,
<br>
<br>There is already something similar in <a title="MbUnit, Generating Unit Testing and Model Based Testing Framework for .NET Framework" href="http://mbunit.tigris.org" target="_blank">MbUnit</a>: the ProcessFixture (<a target="_new" href="http://blog.dotnetwiki.org/archive/2004/04/27/168.aspx">http://blog.dotnetwiki.org/archive/2004/04/27/168.aspx</a>)
<br>
<br>The problem with that fixture is that tests show as one single test case.
<br>
<br>Of course, I'm thinking about the way of adding this functionality to <a title="MbUnit, Generating Unit Testing and Model Based Testing Framework for .NET Framework" href="http://mbunit.tigris.org" target="_blank">MbUnit</a>... so stay tuned.
<br>
<br>As for cyclic dependencies, they are automatically detected by the topological sort (back edges). I am still not sure how to handle them: throw and ignore and add a warning.
<br>
<br>Once it is implemented, we will have 3 levels of dependencies wich should make &quot;branch-and-bound&quot; testing easier...
Jonathan de Halleux
Monday, June 06, 2005 5:24:59 PM UTC
Wow, superb!
<br>Thanks.
Diana
Comments are closed.