Dan*_*own 0 c# unit-testing moq xunit asp.net-core
我正在尝试对一些代码进行单元测试,这些代码使用IServiceProvider和反射的组合来创建扩展抽象类的每个类的实例BaseCommand:
IEnumerable<BaseCommand> commandsInAssembly = typeof(BaseCommand)
.Assembly.GetTypes()
.Where(t => t.IsSubclassOf(typeof(BaseCommand)) && !t.IsAbstract)
.Select(t => (BaseCommand)ActivatorUtilities.CreateInstance(_serviceProvider, t))
.ToList();
Run Code Online (Sandbox Code Playgroud)
这里棘手的部分_serviceProvider是注入并且需要被模拟(我认为),以允许这段代码成功且独立地运行。每个命令都需要访问 DI 以解决其依赖关系。大多数命令看起来类似于:
public SomeCommand(IAppState appState, ILoggerAdapter<SomeCommand> logger) : base(appState)
Run Code Online (Sandbox Code Playgroud)
我能够IServiceProvider很好地模拟来解决IAppState,但我在ILoggerAdapter<>. 这是我目前的设置:
单元测试构造函数
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider
.Setup(x => x.GetService(typeof(IAppState)))
.Returns(new AppState());
serviceProvider
.Setup(x => x.GetService(typeof(ILoggerAdapter<>)))
.Returns(typeof(LoggerAdapter<>));
var serviceScope = new Mock<IServiceScope>();
serviceScope
.Setup(x => x.ServiceProvider)
.Returns(serviceProvider.Object);
var serviceScopeFactory = new Mock<IServiceScopeFactory>();
serviceScopeFactory
.Setup(x => x.CreateScope())
.Returns(serviceScope.Object);
serviceProvider
.Setup(x => x.GetService(typeof(IServiceScopeFactory)))
.Returns(serviceScopeFactory.Object); var mocker = new AutoMocker();
_commandDispatcher = new CommandDispatcher(serviceProvider.Object, _mockAppState.Object, _mockLogger.Object);
Run Code Online (Sandbox Code Playgroud)
这会生成以下错误: System.InvalidOperationException :尝试激活“SomeCommand”时无法解析“ILoggerAdapter`1[SomeCommand]”类型的服务。
如果我尝试更明确地设置我的设置(我想避免这种情况,它会使测试更加脆弱)并使用:
serviceProvider
.Setup(x => x.GetService(typeof(ILoggerAdapter<SomeCommand>)))
.Returns(typeof(LoggerAdapter<SomeCommand>));
Run Code Online (Sandbox Code Playgroud)
但这也会产生错误:System.ArgumentException : Object of type 'System.RuntimeType' cannot be convert to type 'ILoggerAdapter`1[SomeCommand]'。
我读到使用 AutoMocking 容器或 Fixture 可能更合适,但我不确定从哪里开始。我对 C# 中的单元测试相当陌生。
如何在不IServiceProvider爆炸的情况下模拟/提供给我的 SUT ActivatorUtilities.CreateInstance(IServiceProvider, type)?
serviceProvider
.Setup(x => x.GetService(typeof(ILoggerAdapter<>)))
.Returns(typeof(LoggerAdapter<>));
Run Code Online (Sandbox Code Playgroud)
这个设置的问题typeof(ILoggerAdapter<>)是永远不会被解决,它是一个通用类型,所以ILoggerAdapter<SomeCommand>会被解决。
serviceProvider
.Setup(x => x.GetService(typeof(ILoggerAdapter<SomeCommand>)))
.Returns(typeof(LoggerAdapter<SomeCommand>));
Run Code Online (Sandbox Code Playgroud)
通过此设置,您可以解决正确的服务。但是,当您返回表示的实例而不是 的实例时,您返回了错误的结果。您将需要通过-ing 或模拟它来创建一个实例。TypeLoggerAdapter<SomeCommand>LoggerAdapter<SomeCommand>LoggerAdapter<SomeCommand>new
另一个解决方案可能是您不模拟IServiceProvider实例,而是IServiceProvider使用常规 DI 设置创建一个“真实”实例:创建一个新ServiceCollection实例,添加您的服务并调用BuildServiceProvider(). 例如:
var services = new ServiceCollection();
// Add IAppState, ILoggerAdapater, and other services
// Create the service provider instance
var serviceProvider = services.BuildServiceProvider();
// Resolve services from the IServiceProvider and pass it along
var appState = serviceProvider.GetRequiredService<IAppState>();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7659 次 |
| 最近记录: |