My team is in the process of developing a system where we're using Unity as our IoC container; and to provide NHibernate ISessions (Units of work) over each HTTP Request, we're using Unity's ChildContainer feature to create a child container for each request, and sticking the ISession in there.
We arrived at this approach after trying others (including defining per-request lifetimes in the container, but there are issues there) and are now trying to decide on a unit testing strategy.
Right now, the application-level container itself is living in the HttpApplication, and the Request container lives in the HttpContext.Current. Obviously, neither exist during testing.
The pain increases when we decided to use Service Location from our Domain layer, to "lazily" resolve dependencies from the container. So now we have more components wanting to talk to the container.
We are also using MSTest, which presents some concurrency dilemmas during testing as well.
So we're wondering, what do the bright folks out there in the SO community do to tackle this predicament?
How does one setup an application that, during "real" runtime, relies on HTTP objects to hold the containers, but during test has the flexibility to build-up and tear-down the containers consistently, and have the ServiceLocation bits get to those precise containers.
I hope the question is clear, thanks!
Th开发者_开发技巧anks for the replies. I agree that using Service Location is not the optimal approach - but it does seem necessary for this situation. The scenario is that we need our Entities to resolve dependencies, on-demand, only when needed - for business rule validation. Forcing all our entities, on being materialized by NHibernate, to undergo constructor injection, doesn't seem appropriate, at a minimum for performance reasons.
We're considering a solution where the containers are stored either in the HttpApplication/HttpContext at real runtime, and in static/ThreadStatic fields during test. StructureMap has a similar approach baked-in. Any thoughts on this kind of solution? Thanks!
Also, this isn't necessarily integration testing (although it may play into that too). For example, we want to unit-test a particular entity's business rule behavior--during which this scenario will unfold.
I am definitely open to the Http object abstractions - I've used them and loved them in MVC; how can one get them going outside of MVC?
DI Containers should not be necessary during unit testing. Rather, a DI Container is used at application startup time to resolve the application's dependency graph, and then get out of the way.
However, it sounds like you have applied the Service Locator anti-pattern, and you are now feeling the pain of that. Unfortunately, there's no easy way out of this.
You obviously can't rely on the real HTTP Context during unit testing, as it will not be available to you in that environment, so you will need to hide them away behind interfaces. If you are using .NET 3.5 SP1, you might be able to use the abstractions introduced in System.Web.Abstractions, but otherwise, you can extract some yourself.
Once you have introduced these Seams into your system, you can use proper Dependency Injection (preferably Constructor Injection) to inject them into your consuming classes.
In any case, following Test-Driven Development can very effectively prevent this type of tight coupling from being introduced in the first place.
精彩评论