Translate

Friday, 30 April 2010

Unit & Mock Testing "New" and "Override" implementations

It has been quite a while since I posted to my blog because I didn't have anything interesting to publish. But now, here is an interesting challenge. Unit testing the "new" and "override" keyword implementation.

Since, the "new" keyword was introduced to hide a base class implementation there has been a lot of arguments on how to actually show the execution of these methods in a polymorphic perspective.

Below is an example that solidly tests the classes and generates the necessary result.

// Class Under Test

using System;
using NUnit.Framework;
namespace NewAndOverrideTest
{
public class BaseClass
{
protected BaseClass ob;
public BaseClass()
{

}
public virtual BaseClass OverrideMethod()
{
ob = new BaseClass();
Console.WriteLine("Virtual from Base Class");
return ob;
}
}
public class DerivedClass : BaseClass
{
public override BaseClass OverrideMethod()
{
ob = new DerivedClass();
Console.WriteLine("Override from DerivedClass Class");
return ob;
}
}
public class SecondDerivedClass : DerivedClass
{
public new BaseClass OverrideMethod()
{
ob = new SecondDerivedClass();
Console.WriteLine("New from SecondDerivedClass Class");
return ob;
}
}
public class ThirdDerivedClass : SecondDerivedClass
{
public BaseClass OverrideMethod()
{
ob = new ThirdDerivedClass();
Console.WriteLine("New from ThirdDerivedClass Class");
return ob;
}
}
}

// The NUnit Tests

using System;
using NUnit.Framework;
namespace NewAndOverrideTest
{
public class UnitTestOfNewAndOverride
{
[TestFixture]
public class TestNewOverride
{
private BaseClass baseClassObject;
private DerivedClass derivedClassObject;
private SecondDerivedClass secondDerivedClassObject;
[SetUp]
public void InitializeCUTObject()
{
}
[Test]
public void TestTheObjectCallingTheBaseMethod()
{
baseClassObject = new DerivedClass();
Assert.That(baseClassObject.OverrideMethod(), Is.InstanceOf(typeof(DerivedClass)));
}
[Test]
public void TestTheObjectCallingTheSecondDerivedMethod()
{
derivedClassObject = new SecondDerivedClass();
Assert.That(derivedClassObject.OverrideMethod(), Is.InstanceOf(typeof(SecondDerivedClass)));
}

The 2nd test, "TestTheObjectCallingTheSecondDerivedMethod" fails because the instance is pointing to SecondDerivedClass whose "OverrideMethod" is actually a "new" implementation. This causes the execution engine not to look for polymorphic behavior but to call the object instance type's implementation, ie, the DerivedClass OverrideMethod.

The test will pass if Assert statement is changed to query for "InstanceOf(typeof(DerivedClass)".

Below is the same test with Rhino Mock. I have used Rhino Mock just to demonstrate mock testing, with Rhino Mock, in the unit tests. It is a rather contrived example but it serves its purpose.

Rhino Mock 2.6, NUnit 2.5 and .net 2.0 are required to execute the tests and the code.


// The Interface

using System;

namespace NewAndOverrideTest
{
public interface INewOverride
{
void NewMethod();
Object OverrideMethod();
}
}

// The NUnit Test Class
using System;
using NUnit.Framework;
using Rhino.Mocks;
namespace NewAndOverrideTest
{
[TestFixture]
public class TestNewOverride
{
private BaseClass baseClassObject;
private DerivedClass derivedClassObject;
private SecondDerivedClass secondDerivedClassObject;
private ThirdDerivedClass thirdDerivedClassObject;
private MockRepository mockObject;
private INewOverride interfaceObject;
[SetUp]
public void InitializeCUTObject()
{
mockObject = new MockRepository();
interfaceObject = (INewOverride)mockObject.CreateMock(typeof(INewOverride));
}
[Test]
public void TestTheObjectCallingTheBaseMethod()
{
Expect.Call(interfaceObject.OverrideMethod()).Return(typeof(DerivedClass) as object);
mockObject.Record();
baseClassObject = new DerivedClass();
baseClassObject.NewMethod();
mockObject.ReplayAll();
Assert.That(interfaceObject.OverrideMethod(), Is.InstanceOf(typeof(object)));
mockObject.Verify(interfaceObject);
}
[Test]
public void TestTheObjectCallingTheSecondDerivedMethod()
{
Expect.Call(interfaceObject.OverrideMethod()).Return(typeof(SecondDerivedClass) as object);
mockObject.Record();
derivedClassObject = new SecondDerivedClass();
derivedClassObject.NewMethod();
mockObject.Replay(interfaceObject);
Assert.That(interfaceObject.OverrideMethod(), Is.InstanceOf(typeof(object)));
mockObject.Verify(interfaceObject);
}
[Test]
[ExpectedException(typeof(NullReferenceException))]
public void TestTheObjectCallingTheThirdDerivedMethod()
{
Expect.Call(interfaceObject.OverrideMethod()).Throw(new NullReferenceException());
mockObject.Record();
thirdDerivedClassObject = new ThirdDerivedClass();
//thirdDerivedClassObject.NewMethod();
mockObject.Replay(interfaceObject);
Assert.That(interfaceObject.OverrideMethod(), Is.InstanceOf(typeof(Object)));
mockObject.Verify(interfaceObject);
}
}
}

// The CUT (Class Under Test)
using System;

namespace NewAndOverrideTest
{
public class BaseClass:INewOverride
{
protected BaseClass ob;
public BaseClass()
{

}
public void NewMethod()
{
ob = new BaseClass();
Console.WriteLine("Base Class");
}
public Object OverrideMethod()
{
Console.WriteLine("Virtual from Base Class");
return ob as object;
}
}
public class DerivedClass : BaseClass
{
public void NewMethod()
{
ob = new DerivedClass();
Console.WriteLine("DerivedClass Class");
}
public Object OverrideMethod()
{
Console.WriteLine("Override from DerivedClass Class");
return ob as object;
}
}
public class SecondDerivedClass : DerivedClass
{
public void NewMethod()
{
ob = new SecondDerivedClass();
Console.WriteLine("SecondDerivedClass Class");
}
public new Object OverrideMethod()
{
Console.WriteLine("Override from SecondDerivedClass Class");
return ob;
}
}
public class ThirdDerivedClass : SecondDerivedClass
{
public void NewMethod()
{
ob = new SecondDerivedClass();
Console.WriteLine("ThirdDerivedClass Class");
}
public Object OverrideMethod()
{
Console.WriteLine("Override from ThirdDerivedClass Class");
return ob as object;
}
}
}

No comments: