I had always thought StructureMap is just another IOC tool similar to Castle windsor, until yesterday I read Karl Seguin’s Foundations of Programming, Chapter 4, I was shocked immediately by the injectStub method provided by StructureMap, which is now renamed to inject(). I think this explicitly injection is better than TypeMock implicitly mock instance object.
For example, I have an Organization BO,
public static OrganizationBO GetOrganizationBO(int Id) { return DataPortal.Fetch<OrganizationBO>(new SingleCriteria<OrganizationBO, int>(Id)); } private void DataPortal_Fetch(SingleCriteria<OrganizationBO, int> criteria) { OrganizationDTO data = DataAccess.OrganizationRepository().FindById(criteria.Value); if (data != null) { LoadFromDTO(data); } }
The repository is declared in DataAccess class to centralize all the dataaccess coupling inside CALS BOs.
public static IRepository<OrganizationDTO> OrganizationRepository() { // instead of direct coupling return new OrganizationRepository(); // I use StrcutureMap return ObjectFactory.GetInstance<IRepository<OrganizationDTO>>(); }
The content of IOC config file:
<DefaultInstance
PluginType=”DemoApp.Data.Interfaces.IRepository`1,DemoApp.Data” PluggedType=”DemoApp.Data.Repository.OrganizationRepository,DemoApp.Data”
/>
We can also use other different ways to set dependency, like setDefault in code, or search assembly at runtime as shown in this post.
Test code:
[Test] public void CanGetFromInjectedMockRepository() { var mockRepository = new Moq.Mock<IRepository<OrganizationDTO>>(); // Id in MoQ matters. But TypeMock doesn't care. mockRepository.Expect(x => x.FindById(8172)).Returns( new OrganizationDTO { Id = 1, Name = "A test org name" }); ObjectFactory.Inject(typeof(IRepository<OrganizationDTO>), mockRepository.Object); var o = OrganizationBO.GetOrganizationBO(8172); Assert.AreEqual(1, o.Id); Assert.AreEqual("A test org name", o.Name); }
Here is an artile introducing StructureMap, as it mentioned, StrucutreMap is very good choice if you are working on a class has no “constructor injection”, CSLA is one of those!
I have the same feeling, as the author Karl Seguin said, constructor injection doesn’t really solve the extensibility problem; how does someone add(try to replace) a new plug-in without recompiling the entire application?
The problem/drawback to DI is also obvious, the xml config file keeps growing and expanding. The performance and mantiance will become an issue. That’s why Boo was inverted to save / speed up Castle Windsor. But what about structure Map?
Also I need tool / method to test this xml config file, see details here and here. Unfortunately, I couldn’t make this <structuremap.verification> task loaded into NAnt, (maybe this doesn’t exist in those two dlls at all? I can’t tell because NAnt loadTask doesn’t have output). I tried to different folders and also “Forced scan” using <loadtasks> command, neither one works. Thanks God, Jeremy does have another way to test config file,so called smock test:
ObjectFactory.AssertConfigurationIsValid();
Regarding unit-test and mock, I spent a lot time trying to figure out how to reset the default back. It turns out the documented ObjectFactory.resetdefault has been changed to reset.