# Sunday, January 09, 2005

This is a rather funny application of unit testing. Let me state the problem:

We need to write a wrapper for every type that inherits from C. To make sure we don't miss any, we start by writing a combinatorial test that makes sure every type is mapped with a wrapper type*.

[TestFixture]
public class WrapperTest
{
    // get all the types assignable to C, from the assembly SomeAssembly
    [Factory(typeof(Type))]
    public IEnumerable<Type> Types()
    {
        foreach(Type type in SomeAssembly.GetExportedTypes())
        { 
            if (typeof(C).IsAssignableFrom(type))
               yield return type;
        }
    } 

    // tests that all types have a wrapper
    [CombinatorialTest]
    public void EnsureWrapper(
        [UsingFactories("Types")]Type type
    )
    {
        Assert.IsTrue( IsWrapped(type) );
    }
    
    // returns true of the wrapper exists
    private bool IsWrapped(Type type)
    {...}
}

Ok, we can run this test and see a lot of failures. So now we know wich wrapper has to be written.... but wait, why not making the test generate the wrapper as well.

    [CombinatorialTest]
    public void EnsureWrapper(
        [UsingFactories("Types")]Type type
    )
    {
        if (IsWrapped(type))
            return;

        // wrapper not found, 
        // generating the code and dumping it to Console.Out
        ...

        Assert.Fail("Wrapper not found");
    }

Now, we have test cases that give us the fix in case of a failure :)

*: this could be done by a FxCop rule as well since it is pure static analysis.

posted on Sunday, January 09, 2005 4:13:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [5]
# Saturday, January 08, 2005

Updated Reflector.Framework for Reflector 4.1.27.0.

This version has an automatic *non-intrusive* checking for available updates... based on ProjectDistributor web services :) 

Download it here

posted on Saturday, January 08, 2005 8:44:00 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]
# Friday, January 07, 2005

ProjectDistributor is a new actor on the scene of inline project managment (thanks for Darren). It provides a simple web site for publishing your little cool applications that have been sleeping on your desktop.

Unlike the big guns like sourceforge, tigris or gotdotnet, ProjectDistributor is simple simple simple. With RSS and webservices, it has the vitual but no more features, anyway who uses all the feature from sf or tigris ?

I've decided to use ProjectDistributor to publish my snippets and other useless samples. Currently, the following applciations are already there:

ps: ProjectDistributor.AutoUpdate is a micro autoupdate framework for your application based on projectdistributor. The next release of the addins with support that .... and have their “Check for Addin update” button :)

posted on Friday, January 07, 2005 5:57:00 AM (Pacific Standard Time, UTC-08:00)  #    Comments [4]
# Monday, January 03, 2005

Mike Gunderloy has posted a nice introductory article on using TD.NET and MbUnit in Visual Studio. Check it out at http://www.developer.com/net/net/article.php/3453121

This article is really about TD.NET as Mike emphasis on one of the zillions of feature of TD.NET. There are a lot of very nice feature in TD.NET, just take a moment to discover them.

Going beyond Mike sample with MbUnit

Mike illustrates the article with a little class that stores an integer and returns information such as IsPositive, etc... In the article, Mike uses the canonical fixture. Let's if we can do better. (disclaimer: my VB is really bad)

RowFixture

Typically, you want to test this for 'interresting' values such 0,-1,1,MaxInt,etc... This example really fits well into the example of the RowFixture:

Imports System
Imports MbUnit.Core.Framework
Imports MbUnit.Framework

<TestFixture()> _
Public Class NumberTests
    ...

    <RowTest()> _
    <Row(5,FALSE)> _
    <Row(8,TRUE)> _
    Public Sub TestIsEven(int value, Boolean isEven)
        ' Make sure even numbers are property identified
        Dim num As New Number
        num.Value = value;
        Assert.AreEqual(isEven, num.IsEven)
    End Sub

End Class

This will create a test case for each RowAttribute. Better readibabilty, better test separation. Now can we do better ?

Combinatorial test

Let's try another approach. We could create a table of 'interresting' number with their properties (is positive, is even). Once this is done, we can feed this table to combinatorial tests.

<TestFixture()> _
Public Class NumberTests

    Public Class NumberRow
        Public int Value
        Public bool IsPositive
        Public bool IsEven

        Public New(int value, bool isPositive, bool isEven)
            Me.Value = value
            Me.IsPositive = IsPositive
            Me.IsEven = isEven
        End New
    End Class

    <Factory()> _    
    Public Function Numbers() as Array Of NumberRow
        Dim numbers As New Array Of NumberRow[4];

        numbers[0] = New NumberRow(-1, False, False)
        numbers[1] = New NumberRow(0, False, True)
        numbers[2] = New NumberRow(1, True, False)
        numbers[3] = New NumberRow(2, True, True)

        Return numbers
    End Function
    
    <CombinatorialTest()> _
    Public Sub TestIsEven(<UsingFactories("NUMBERS")> _ NumberRow row)
        ' Make sure even numbers are property identified
        Dim num As New Number
        num.Value = row.Value;
        Assert.AreEqual(row.IsEven, num.IsEven)
    End Sub

End Class

This will create 4 test cases, one per element of the array returned by Numbers. Moreover, we could reuse Numbers in another test to verify IsPositive.

[Update]
If you plan to reuse the factory, you can extract it into a separate class and pass the facotry type of the UsingFactories parameter.

Public Class NumberRow
    Public int Value
    Public bool IsPositive
    Public bool IsEven

    Public New(int value, bool isPositive, bool isEven)
        Me.Value = value
        Me.IsPositive = IsPositive
        Me.IsEven = isEven
    End New
End Class

Public Class NumberFactory
    <Factory()> _    
    Public Function Numbers() as Array Of NumberRow
        Dim numbers As New Array Of NumberRow[4];

        numbers[0] = New NumberRow(-1, False, False)
        numbers[1] = New NumberRow(0, False, True)
        numbers[2] = New NumberRow(1, True, False)
        numbers[3] = New NumberRow(2, True, True)

        Return numbers
    End Function
End Class

<TestFixture()> _
Public Class NumberTests
    
    <CombinatorialTest()> _
    Public Sub TestIsEven(<UsingFactories(CType(NumberFactory))> _ NumberRow row)
        ' Make sure even numbers are property identified
        Dim num As New Number
        num.Value = row.Value;
        Assert.AreEqual(row.IsEven, num.IsEven)
    End Sub

End Class
posted on Monday, January 03, 2005 10:48:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [11]

The Reflector addin download have been down for a long time and I apologize for that (vacations).

Released in 3 flavors

There has been a significant refactoring of the addins so stay tuned: the addins are now separated in 3 assemblies: Reflector.CodeMetrics, Reflector.Graph and Reflector.Framework

  • Reflector.CodeMetrics has no dependency on NGraphviz,
  • Reflector.Graph contains graph stuff only, dependency on NGraphviz
  • Reflector.Framework contains CodeMetrics, Graph, and the all the rest. It is compiled against 1.1
  • you should not mix those 3 builds. Pick the one you want but don't mix them!

New project web site

The addins are now hosted on the excellent http://projectdistributor.net/Groups/Group.aspx?groupId=34. Make sure you monitor the rss to be notified for the updates.

posted on Monday, January 03, 2005 5:06:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]