First, we need to create a IocContainer with a static field IWindsorContainer, this idea is from Steven Rockarts. I added a setter to container property, which will make my later unit-test live much easier. The reason is, CSLA does not implement DI (Datacontext or datarepository is hidden in BO base object).
Somewhere in my application’s initialize period, I should do IocContainer init, do does my unit test setup.
IocContainer.Container = new WindsorContainer(new XmlInterpreter(new ConfigResource(“castle”)));
The new CSLA BO’s dataaccess functions look like this:
public static Trainee GetTrainee(int traineeId)
{
return GetTrainee(traineeId, IocContainer.Container.Resolve<ITraineeRepository>());
}
public static Trainee GetTrainee(int traineeId, ITraineeRepository dtx)
In my test, create 2 mock repository classes:
class TraineeRepositoryMock : ITraineeRepository
{
public SerializableEntity<DalLinq.Trainee> GetTrainee(int id)
{
Gain.DalLinq.Trainee t = new Gain.DalLinq.Trainee();
t.Given_Names = “FFFFF”;
SerializableEntity<Gain.DalLinq.Trainee> st = new SerializableEntity<DalLinq.Trainee>(t);
return st;
}
public virtual int SaveTrainee(DalLinq.Trainee obj, DalLinq.Trainee original)
{
Console.WriteLine(“Hi, fake normal update!”);
return 0;
}
}
class TraineeRepositoryMockFalseUpdate : TraineeRepositoryMock
{
override public int SaveTrainee(DalLinq.Trainee obj, DalLinq.Trainee original)
{
Console.WriteLine(“Hi, false update!”);
return -1122;
}
}
The second one is to created to test the update failure exception handling.
The castle config file:
<configSections>
<section name=”castle”
type=”Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor” />
<section name=”cc2″
type=”Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor” />
</configSections>
<castle>
<components>
<component id=”traineeRepositoryMock” type=”Gain.Library.Test.TraineeRepositoryMock, Gain.Library.Test”
service=”Gain.DalLinq.ITraineeRepository, Gain.DalLinq” />
</components>
</castle>
<cc2>
<components>
<component id=”traineeRepositoryMockFalseUpdate” type=”Gain.Library.Test.TraineeRepositoryMockFalseUpdate, Gain.Library.Test”
service=”Gain.DalLinq.ITraineeRepository, Gain.DalLinq” />
</components>
</cc2>
The whole unit-test:
[TestFixture]
public class TraineeDATestMock
{
[SetUp]
public void SetUp()
{
IocContainer.Container = new WindsorContainer(new XmlInterpreter(new ConfigResource(“castle”)));
}
[Test]
public void CanGetTraineeTroughMockRepository()
{
Trainee item = Trainee.GetTrainee(2);
Assert.AreEqual(“FFFFF”, item.GivenNames);
}
[Test]
[ExpectedException(typeof(DataPortalException))]
public void CanCatchUpdateTraineeException()
{
// use the new IocContainer to read those false update mock repository.
IocContainer.Container = new WindsorContainer(new XmlInterpreter(new ConfigResource(“cc2”)));
Trainee oldTrainee = Trainee.GetTrainee(2);
oldTrainee.GivenNames = “BBBB”;
oldTrainee.Save();
}
[Test]
public void CanUpdateTrainee()
{
Trainee oldTrainee = Trainee.GetTrainee(2);
oldTrainee.GivenNames = “AAAA”;
Trainee newTrainee = oldTrainee.Save();
Assert.AreEqual(“AAAA”, newTrainee.GivenNames);
}
}
I think this way of unit-test CSLA BO is clearer than TypeMock. We should try to avoid to use TypeMock, unless you are testing a legacy app, as Billy McCaffery pointed out:
a tool such as TypeMock should be used only when absolutely necessary as it can lead to habits of not programming-to-interface.
In fact, those ‘Mock’ objects I created should be called stub. A stub is a class that is hard-coded to return data from its methods and properties. Thanks to Jeremy Miller for clarification.
My question is, becuase TypeMock doesn’t work with castle windsor container, can I use Rhino Mock to mock this internal/private Repository object instead of using stub + switching different castle config file?