Clara's Notes on Technology

Just a place to put down ideas and concepts on technology, mainly .NET, BizTalk, SQL Server, and other MSFT stuff.

Sunday, November 05, 2006

From NUnit to Team System

Another chapter on my experience helping a client adopt Team System.

This time, the goal was to convert their NUnit test to Team System tests. This is not a very difficult topic given the great conversion tool available on gotdotnet (here), which basically does all the work for you. However, I did stumble upon a few issues. Before going into that, this is the basic procedure I followed (fortunately, NUnit tests were already placed in a single project (*.Test)):

a. Create a new test project (named *.Test.TS)
b. Create the necessary project folders
c. Add the necessary references
d. Copy *.cs files from *.Test project to *.Test.TS
e. Set project properties if necessary (build location, postbuild events, etc.)
f. Build
g. Perform a test run with NUnit to check everything is green
h. Run the NUnit Converter
i. Remove Nunit references and build again
j. Run tests in TS and check results with corresponding run in Nunit (g)
k. Commit pending changes

When the test project is created, a .vsmdi and a .testrunconfig file are also created and added to the soluiton folder. If new tests are added to the solution, the vsmdi file will need to be checked out. To see all the tests available for the solution, open .vsmdi file (it offers a list view of the test which can be sorted and grouped -- n.b. the possibility of grouping tests into lists is only available if you have VS Team Edition for Testers).

When converting a large project (about 2000 tests), I had to get around the following issues:

1. Category Attribute

Categories do not exist in Team System. The alternative is to use Description attribute or lists (lists are only available in the Tester edition). The converter tool reacts as follows when finding a Category attribute:


  • If just one category on a test method, conversion was as follows: [Test, Category("sample")] --> [TestMethod(), TestProperty("Category", "sample")]


  • If just one category on a class, conversion was as follows: [TestFixture, Category("sample")] --> //Category: "sample"


  • If more than one category attribute, conversion did not occur and NUnit conversion tool stops. My solution here was pretty basic: manual replacement (I used TextPad as editor)

  • Replace Category("\(.+\)"),Category("\(.+\)")\] by Category("\1")]\n[TestProperty("Category","\2")\]


    For instance: [Test, Category("Business"), Category("More Business")] becomes [Test, Category("Business")] [TestProperty("Category","More Business")]


    Notice that this is just a temporary solution to get the converter tool to run until the end. The final conversion gives this [TestMethod(), TestProperty("Category","Business")] [TestProperty("Category","More Business")] which is not correct because the same property is used twice with different values. The second property should be changed to TestProperty("Category2","More
    Business")
    , for example (or use Description attribute instead).


2. Partial Classes

Partial classes are not converted because they do not have the TestFixture attribute. You need to add it in order for the conversion to run, but afterwards remvoe the
corresponding TestClass attribute (because it is a duplicate given that the class was partial).


3. Static Methods.

Due to the TestFixtureSetUp conversion to ClassInitialize(), some methods had to be converted to static. Also, since the initialize method is now static, it cannot be overriden
anymore, but it doesn't really matter because of point 4.

Let me explain. The initial scenario was as follows: you have a set of test classes that inherit from a parent class. This parent class contains a test set up method used by almost all children. Those that need some extra/different initialization override the method. Like this:


[TestFixture]
public class BaseTest
{
[TestFixtureSetUp]
public virtual void InitializeTests()
{
// do some initialization
}
}

[TestFixture]
public class MyTest1 : BaseTest
{
[Test]
public voic SomeTest
{
base.InitializeTests();
// do other things
}
}

[TestFixture]
public class MyTest2 : BaseTest
{
[Test]
public voic SomeOtherTest
{
base.InitializeTests();
// do other things
}

public override void InitializeTests()
{
// do some other initialization
}
}


This scenario does not work anymore in Team System because of points
3 and 4 (initialize methods are static and inheritance is not supported.

4. Inheritance is not supported in Team System unit tests.

Yes, that is disappointing. This explains why the [TestFixtureSetUp] methods in a parent classes is not called. In Team System testing framework there are 3 attributes to initialize/clean up tests:


  • TestInitialize/CleanUp

  • ClassInitialize/Cleanup. It replaces your TestFixtureSetUp/TearDown but remember that inheritance is not supported.

  • AssemblyInitialize/Cleanup It runs once at the start of each method in the assembly.

You should use these attributes. My recommended solution is to replace the TestFixtureSetUp attributes (converted to ClassInitialize()) in a parent class by AssemblyInitialize and reorganize tests so that all tests needing this particular initialization are in this assembly.

Given the example above, this means removing inheritance, adding an AssemblyInitialize on the InitializeTests method, and moving the MyTest2 class to another assembly (if you do not want it to use the InitializeTests at all) or adding a TestInitialize method to MyTest2.InitializeTests (if you want to add some extra initialization specific to SomeOtherTest).

5. Missing TestFixture attribute

If a class does not have the [TestFixture] attribute, it is not converted (even if it contains test methods).

0 Comments:

Post a Comment

<< Home