【发布时间】:2022-09-24 17:49:19
【问题描述】:
我为 Microsoft DependencyInjection 创建了一个包装类,以简化我的应用程序中的一些调用。我正在尝试编写使用 Moq 将对象插入依赖注入服务的单元测试。
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;
public static class DiService
{
private static IServiceProvider diProvider;
private static Dictionary<Type, object> mockCollection = new Dictionary<Type, object>();
public static IServiceCollection ServiceCollection { get; } = new ServiceCollection();
public static bool UseTestMode { get; set; } = false;
public static T GetRequiredService<T>()
where T : class
{
if( UseTestMode )
{
if( mockCollection.ContainsKey(typeof(T)) )
{
return mockCollection[typeof(T)] as T;
}
}
if( diProvider == null )
{
diProvider = ServiceCollection.BuildServiceProvider();
}
return diProvider.GetRequiredService<T>();
}
public static void RegisterMock(Type interfaceType, object mockObjectInstance)
{
if( !mockObjectInstance.GetType().IsInstanceOfType(interfaceType) )
{
throw new InvalidCastException($\"mockObjectInstance must be of type {interfaceType}\");
}
if( mockCollection.ContainsKey(interfaceType) )
{
mockCollection[interfaceType] = mockObjectInstance;
}
else
{
mockCollection.Add(interfaceType, mockObjectInstance);
}
}
}
测试相关代码
public interface ITestInterface
{
}
public class TestClass : ITestInterface
{
}
[Fact]
public void GetRequiredService_MoqObject_NormalOperation()
{
Mock<ITestInterface> mock = new Mock<ITestInterface>();
DiService.UseTestMode = true;
DiService.RegisterMock(typeof(ITestInterface), mock.Object);
ITestInterface testResult = DiService.GetRequiredService<ITestInterface>();
Assert.NotNull(testResult);
}
这对于我自己很棒的模拟非常有用,但当我尝试使用 Moq 时却不行。为 Moq 对象抛出 InvalidCastException。
在RegisterMock 方法中,我无法弄清楚如何转换 Moq 对象以检查它是否实现了正确的接口。 Moq 对象实际上并没有从它所模拟的接口继承(接口是ITestInterfaceProxy)。我也无法弄清楚如何将对象转换为由变量指定的类型。
有没有办法在RegisterMock 中实际执行错误检查?
提前感谢您的回复。
附录:
根据 Peter Csala 的评论,我添加了这个示例,说明我如何使用上面的 DiService。我希望我没有将它简化到无用的地步。
[Fact]
public void TestLoad()
{
DiService.UseTestMode = true;
Mock<IDataAccess> mockDataAccess = new Mock<IDataAccess>();
DiService.RegisterMock(typeof(IDataAccess), mockDataAccess.Object);
Data testData = GenFu.A.New<Data>();
mockDataAccess.Setup(mock => mock.LoadData(It.IsAny<string>()).Returns(testData);
// Assuming that inside MyViewModel.LoadData there is some process that generates an IDataAccess and calls IDataAccess.LoadData
MyViewModel viewModel = new MyViewModel();
Data loadedData = viewModel.LoadData(\"some id\");
Assert.Equal(testData, loadedData);
}
-
等什么???你想测试一个在正常模式和测试期间工作方式不同的类吗?为什么?
-
好吧,当您测试一个注入了其依赖项的类时,模拟这些依赖项是很常见的。从这个意义上说,类的生产依赖项与测试的依赖项不同,所以是的,从技术上讲它是不同的。重点是测试除依赖关系之外的类中的逻辑。我上面所说的旨在提供在测试其他类时提供注入依赖项的方法,我只是想证明它可以通过单元测试工作。
-
我还应该说,我还没有找到通过正常路由将 Moq 对象注入依赖注入服务的方法,因为 Moq 对象没有从它所模拟的接口继承。哦,DI 服务会自动创建所需对象的实例。我在测试时不希望这样。我想要一个可以操作的特定对象。