xUnit测试问题:如何模拟ClassA工厂以测试依赖该工厂的ClassB
解决方案
一、单元测试工厂Mock逻辑编写
你注入的Func<int, IClassA>本质是入参为int、返回值为IClassA的委托,有两种常用实现方式:
方式1:直接构造工厂委托(无Mock库也可使用,适合简单场景)
不需要引入Mock框架就能直接实现,代码如下:
[Fact] public void TestClassBReturnsCorrectString() { // Arrange // 直接构造符合要求的工厂委托 Func<int, IClassA> mockClassAFact = (inputNumber) => { // 逻辑简单的场景可以直接返回真实ClassA实例 return new ClassA(inputNumber); // 如果IClassA有复杂外部依赖需要Mock,用Moq写法如下 // var mockClassA = new Mock<IClassA>(); // mockClassA.Setup(x => x.ReturnString()).Returns(inputNumber.ToString()); // return mockClassA.Object; }; IClassB classB = new ClassB(mockClassAFact); // Act string aString = classB.ExampleFct(); // Assert Assert.Equal("5", aString); // 推荐用Equal代替True判断,报错信息更清晰 }
注:你提供的ClassB代码中
IClassA classA = _classAFactory(_exampleValue)行末尾缺少分号,会导致编译报错,需要补充。
方式2:带调用验证的Moq实现
如果需要验证工厂的调用次数、传入参数是否符合预期,可以用Moq框架做更严谨的校验:
[Fact] public void TestClassBReturnsCorrectString_WithVerify() { // Arrange var mockClassA = new Mock<IClassA>(); mockClassA.Setup(x => x.ReturnString()).Returns("5"); // 模拟工厂,验证传入参数是5时返回模拟的IClassA实例 var mockFactory = new Mock<Func<int, IClassA>>(); mockFactory.Setup(f => f.Invoke(It.Is<int>(v => v == 5))).Returns(mockClassA.Object); IClassB classB = new ClassB(mockFactory.Object); // Act string aString = classB.ExampleFct(); // Assert Assert.Equal("5", aString); // 额外验证调用逻辑是否符合预期 mockFactory.Verify(f => f.Invoke(5), Times.Once); mockClassA.Verify(x => x.ReturnString(), Times.Once); }
二、Autofac 场景专用解决方案
Autofac本身内置对委托工厂的支持,同时提供了测试专用的扩展包:
业务代码注册方案
正常业务代码中不需要手动注册Func<int, IClassA>工厂,Autofac会自动识别该类型依赖,你只需要注册基础服务即可:
// Autofac服务注册 builder.RegisterType<ClassA>().As<IClassA>(); builder.RegisterType<ClassB>().As<IClassB>();
完成上述注册后,Autofac会自动生成符合要求的工厂实例注入ClassB构造函数。
单元测试专用方案
测试场景可以使用官方的Autofac.Extras.Moq扩展包,自动处理所有依赖的Mock逻辑,无需手动构造工厂:
- 先安装NuGet包:
Autofac.Extras.Moq - 测试代码如下:
[Fact] public void TestClassBWithAutofacMoq() { using var mock = AutoMock.GetLoose(); // 配置IClassA的模拟返回 mock.Mock<IClassA>().Setup(x => x.ReturnString()).Returns("5"); // Autofac自动生成Func<int, IClassA>工厂实现,直接创建ClassB实例即可 var classB = mock.Create<ClassB>(); // Act var result = classB.ExampleFct(); // Assert Assert.Equal("5", result); // 同样支持调用逻辑验证 mock.Mock<Func<int, IClassA>>().Verify(f => f.Invoke(5), Times.Once); }
内容的提问来源于stack exchange,提问作者RadioMan85
相关产品推荐
相关产品推荐

