IOC Container in CSLA

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?

Advertisements

3 thoughts on “IOC Container in CSLA

  1. Frank,
    Typemock can work with Castle windsor, you don’t even have to change the configuration file (leading to having your tests spread out in many files – making it harder to maintain)
    actually with Typemock many teams start by writing code in any design and slowly refactor it to make it better.

    Then instead of manually writing the mocks, you have a framework that can do it for you and handle future changes to the interface in a better way.

    In any case beware that too much programming to interfaces can be a code smell too.

  2. Sorry, Eli. I don’t what’s wrong on my machine, today, I re-tried all the test, it turns out TypeMock works great with IOC!

    Now my revised test code should be like this: NO Stub at all!

    [Test]
    [ExpectedException(typeof(DataPortalException))]
    public void CanCatchUpdateTraineeExceptionUsingTypeMock()
    {
    DalLinq.Trainee t = new DalLinq.Trainee();
    t.Given_Names = “Herby”;
    SerializableEntity st = new SerializableEntity(t);

    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
    ITraineeRepository dtx = (ITraineeRepository)IocContainer.Container.Resolve();
    dtx.GetTrainee(1);
    recorder.Return(st);
    dtx.SaveTrainee(t, t);
    recorder.Return(-1122);
    }

    Trainee oldTrainee = Trainee.GetTrainee(2);
    oldTrainee.GivenNames = “Herby”;
    oldTrainee.Save();

    }

    I start to like typeMock now. But, how come “too much programming to interfaces can be a code smell too.”?? I thought that’s the right way to go.

  3. I don’t like the static field idea.
    What we do in our projects is add the instance of the container to the container itself.
    This way your components can access it through regular .ctor/setter injection.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s