ASP. NET series: StructureMap for unit testing,
When ASP. NET uses StructureMap and other dependency injection components, the most important thing is that the DbContext object of EntityFramework must have only one DbContext instance in each HttpRequest. Here, the HttpSimulator provided by a third party is used for testing.
1. Define the IDependency Interface
Creates an interface to shield different dependency injection components from different use cases.
public interface IDependency{ void Build(); void EndRequest(); void AddTransient(Type from, Type to, object instance = null); void AddScoped(Type from, Type to, object instance = null); void AddSingleton(Type from, Type to, object instance = null); object GetInstance(Type type); IEnumerable GetAllInstances(Type type);}
2. uremap adaptation class StructureMapAdapter
public class StructureMapAdapter : IDependency, IDisposable{ private bool _disposed = false; private Container _container; private Registry _registry; public StructureMapAdapter() { this._registry = new Registry(); } public void Build() { _container = new Container(_registry); } public void EndRequest() { HttpContextLifecycle.DisposeAndClearAll(); } public void AddTransient(Type from, Type to, object instance = null) { if (instance == null) { _registry.For(from).Use(to).LifecycleIs<TransientLifecycle>(); } else { _registry.For(from).Use(instance).LifecycleIs<TransientLifecycle>(); } } public void AddScoped(Type from, Type to, object instance = null) { if (instance == null) { _registry.For(from).Use(to).LifecycleIs<HttpContextLifecycle>(); } else { _registry.For(from).Use(instance).LifecycleIs<HttpContextLifecycle>(); } } public void AddSingleton(Type from, Type to, object instance = null) { if (instance == null) { _registry.For(from).Use(to).LifecycleIs<SingletonLifecycle>(); } else { _registry.For(from).Use(instance).LifecycleIs<SingletonLifecycle>(); } } public object GetInstance(Type type) { return _container.GetInstance(type); } public IEnumerable GetAllInstances(Type type) { return _container.GetAllInstances(type); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { this._container.Dispose(); } _disposed = true; } }}
3. Use HttpSimulator for unit testing
public class StructureMapAdapterTest{ [Fact] public void TransientTest() { IDependency dependency = new StructureMapAdapter(); dependency.AddTransient(typeof(ITest), typeof(Test)); dependency.Build(); var version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; var version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; Assert.NotEqual(version1, version2); } [Fact] public void SingletonTest() { IDependency dependency = new StructureMapAdapter(); dependency.AddSingleton(typeof(ITest), typeof(Test)); dependency.Build(); var version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; var version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; Assert.Equal(version1, version2); } [Fact] public void ScopedTest() { var version1 = ""; var version2 = ""; using (HttpSimulator simulator = new HttpSimulator()) { IDependency dependency = new StructureMapAdapter(); dependency.AddScoped(typeof(ITest), typeof(Test)); dependency.Build(); simulator.SimulateRequest(new Uri("http://localhost/")); version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; Assert.Equal(version1, version2); } using (HttpSimulator simulator = new HttpSimulator()) { IDependency dependency = new StructureMapAdapter(); dependency.AddScoped(typeof(ITest), typeof(Test)); dependency.Build(); simulator.SimulateRequest(new Uri("http://localhost/")); version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; } using (HttpSimulator simulator = new HttpSimulator()) { IDependency dependency = new StructureMapAdapter(); dependency.AddScoped(typeof(ITest), typeof(Test)); dependency.Build(); simulator.SimulateRequest(new Uri("http://localhost/")); version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; } Assert.NotEqual(version1, version2); }}public interface ITest{ String Version { get; }}public class Test : ITest{ private string _version = Guid.NewGuid().ToString(); public string Version { get { return this._version; } }}
Running result: