WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Unit Testing in .NET Projects
Pages: 1, 2, 3, 4, 5

MbUnit

This is where we see some of the most innovative work in unit testing, regardless of language. There are 11 types of test fixtures, nine types of tests, and a myriad of other attributes to be applied. What one can do with MbUnit boggles the mind. So let's start with something reasonable; let's build on an existing example.




[RowTest()]
[Row(1,2,3)]
[Row(2,3,5)]
[Row(3,4,8)]
[Row(4,5,9)]
public void tAdd(Int32 x, Int32 y, Int32 expectedSum)
{
  Int32 Sum;
  Sum = this.Subject.Add(x,y);
  Assert.AreEqual(expectedSum, Sum);
}

The attribute Test has been replaced with RowTest. The attribute Row decorates providing data to be passed as parameters to the test. Notice the signature to the test: (Int32 x, Int32 y, Int32 expectedSum). MbUnit's test runner will run the test for as many Row decorators have been applied; four, in this case. And yes, the test runner will count them as separate tests. The results of running these tests would be four tests run, three passed, one failed. The RowTest leads into the XMLDataProvider attribute. It is similar to the functionality of a FitNesse fixture. The general idea is to provide an XML file and XPath query. The test runner will loop through the nodes, passing the node or (if desired) deserializing the node and passing it as a parameter to the test. Again, the test runner will count each run of the test as a test (i.e., three nodes would be counted as three tests). Jumping up in complexity, MbUnit provides advanced fixtures like the attribute TestSuite, which can be combined with other features like reflection to produce a test like this:


[TestSuite]
public TestSuite TestGenerator(){
  this.LoadAssemblies(); 
  TestSuite suite = new TestSuite("ExceptionSuite"); 
  foreach (Assembly Asm in AppDomain.CurrentDomain.GetAssemblies()) 
  { 
    if (!(Asm.FullName.StartsWith("MbUnit"))) 
    { 
      foreach (Type Tp in Asm.GetExportedTypes()) 
      { 
        if (Tp.IsSubclassOf(typeof(Exception))) 
        { 
          suite.Add(Tp.FullName, new TestDelegate(GenericTest), Tp);
        } 
      } 
    } 
  } 
  return suite;
}

The method decorated with the attribute TestSuite must return a TestSuite. To add to the TestSuite, a name for the test and an instance of the delegate TestDelegate must be provided. In the example, we will be testing the serialization and deserialization of exceptions. You will be surprised at how many types of exceptions are not able to be serialized or deserialized. The method LoadAssemblies reads a config file and loads all assemblies specified. A test is added to the TestSuite for each type found that is derived from Exception.


public void GenericTest(Type exceptionType){
  if (exceptionType == typeof(System.Data.SqlTypes.SqlTypeException))
  { 
    Assert.Ignore("The type {0} does not implement ISerializable correctly.", 
                  exceptionType.FullName);
  } 
  else if (exceptionType == typeof(System.Data.SqlTypes.SqlNullValueException))
  { 
    Assert.Ignore("The type {0} does not implement ISerializable correctly.", 
                  exceptionType.FullName);
  } 
  else if (exceptionType == typeof(System.Data.SqlTypes.SqlTruncateException))
  { 
    Assert.Ignore("The type {0} does not implement ISerializable correctly.", 
                  exceptionType.FullName);
  }

The method GenericTest was provided as the delegate for each test. Notice the parameter exceptionType; it was specified when the test was added to the TestSuite. The next interesting thing is MbUnit's ability to dynamically ignore a unit test. Here we are ignoring the SqlTypes exceptions because they do not implement ISerializable correctly.


Exception ThrownException = null; 
Stream Stream = null; 
Exception Clone = null; 

try 
{ 
  throw ((Exception)(this.ClassFactory.CreateInstanceOf(exceptionType))); 
} 
catch (Exception ex) 
{ 
  if (ex.GetType() == exceptionType) 
  { 
    ThrownException = ex; 
  } 
  else 
  { 
    Assert.Ignore(string.Format("Not able to create {0} {1}", 
                                exceptionType.FullName, ex.ToString())); 
  } 
}

Pages: 1, 2, 3, 4, 5

Next Pagearrow