ASP.NET 系列:单元测试之StructureMap
ASP.NET使用StructureMap等依赖注入组件时最重要就是EntityFramework的DbContext对象要保证在每次HttpRequest只有一个DbContext实例,这里将使用第三方提供的HttpSimulator进行测试。
1.定义IDependency接口
创建屏蔽不同依赖注入组件使用差别的接口。
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.提供StructureMap的适配类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.使用HttpSimulator进行单元测试
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; } } }
运行结果:
您的推荐,我的动力。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?