单元测试调用IServiceProvider.GetRequiredService遇注册错误如何解决?
问题:单元测试Foo.Get()时抛出DI注册异常
现有类Foo通过构造函数注入IServiceProvider,其Get()方法依赖GetRequiredService获取实例。单元测试调用Get("a")时抛出System.InvalidOperationException,提示"No service for type 'MyType' has been registered"。限制条件:
- 无法修改
Foo类及Get()方法实现 - 无法Mock框架扩展方法
IServiceProvider.GetRequiredService
实现代码:
public class Foo { private IServiceProvider _serviceProvider; public Foo(IServiceProvider serviceProvider, IOtherService s1, IOtherService2 s2){ _serviceProvider = serviceProvider; //...mapping other dependencies here } public IType Get (string type){ switch (type){ case "a": return (IType)_serviceProvider.GetRequiredService(typeof(MyType)); //other cases here //...... } } }
当前单元测试代码(使用NUnit、Autofac.Extras.Moq、Moq):
[Test] public void MyTest() { using var am = AutoMock.GetLoose(); var foo= am.Create<Foo>(); //DI Exception when calling this method //No service for type 'MyType' has been registered foo.Get("a"); //Assert here //.... }
可行解决方案
方案1:通过Autofac.Extras.Moq注册所需服务
AutoMock基于Autofac容器实现,直接将MyType注册到容器中,让IServiceProvider能正常解析该类型:
[Test] public void MyTest() { using var am = AutoMock.GetLoose(); // 将MyType注册到AutoMock的容器,关联到IType接口 am.ContainerBuilder.RegisterType<MyType>().As<IType>(); var foo = am.Create<Foo>(); // 调用Get("a")可正常获取实例 var result = foo.Get("a"); // 验证返回实例类型符合预期 Assert.IsInstanceOf<MyType>(result); }
如果MyType自身有依赖,可通过AutoMock自动注入,或手动注册其依赖项。
方案2:手动实现Mock版IServiceProvider
若不想依赖Autofac容器,可自定义一个简单的IServiceProvider实现,模拟服务解析逻辑(GetRequiredService扩展方法最终会调用GetService):
public class MockServiceProvider : IServiceProvider { private readonly Dictionary<Type, object> _services = new Dictionary<Type, object>(); public void Register<T>(T instance) { _services[typeof(T)] = instance; } public object GetService(Type serviceType) { _services.TryGetValue(serviceType, out var instance); return instance; } }
测试时使用该模拟类:
[Test] public void MyTest() { // 创建模拟服务提供者并注册MyType实例 var mockServiceProvider = new MockServiceProvider(); var myTypeInstance = new Mock<IType>().Object; // 可根据需求Mock MyType的行为 mockServiceProvider.Register<MyType>(myTypeInstance); // 手动构造Foo实例,注入其他依赖的Mock对象 var s1Mock = new Mock<IOtherService>(); var s2Mock = new Mock<IOtherService2>(); var foo = new Foo(mockServiceProvider, s1Mock.Object, s2Mock.Object); var result = foo.Get("a"); Assert.IsInstanceOf<IType>(result); // 可额外验证MyType的行为逻辑 }
注意:GetRequiredService会检查GetService返回值是否为null,确保注册的服务实例不为null即可避免异常。
内容的提问来源于stack exchange,提问作者Nilmi Nawalage
相关产品推荐
相关产品推荐

