如何用AutoFixture创建实现多个接口的Mock对象?
问题描述
待测试代码如下:
public class MyClass { private InterfaceA _thing; MyClass(InterfaceA thing) { _thing = thing; } public MyType MyMethod() { if (_thing is InterfaceB bThing) { return bThing.MethodOnB(); } } }
测试需求:需要将_thing模拟为同时实现InterfaceA和InterfaceB的对象,以便指定InterfaceB.MethodOnB()的返回值或验证调用情况,并且希望通过自定义属性将该模拟对象作为测试方法参数注入,遵循AutoFixture的推荐用法。
解决方案
结合AutoFixture和Moq,通过自定义属性实现多接口模拟对象的注入,具体步骤如下:
1. 自定义AutoFixture属性类
创建继承自CustomizeAttribute的属性类,配置AutoFixture生成同时实现两个接口的模拟对象:
using AutoFixture; using AutoFixture.AutoMoq; using AutoFixture.Kernel; using System; [AttributeUsage(AttributeTargets.Parameter)] public class MockBothInterfacesAttribute : CustomizeAttribute { public override ICustomization GetCustomization(ParameterInfo parameter) { return new MockBothInterfacesCustomization(); } private class MockBothInterfacesCustomization : ICustomization { public void Customize(IFixture fixture) { fixture.Customizations.Add(new MockBothInterfacesSpecimenBuilder()); } } private class MockBothInterfacesSpecimenBuilder : ISpecimenBuilder { public object Create(object request, ISpecimenContext context) { var type = request as Type; if (type == typeof(InterfaceA) || type == typeof(object)) { var mock = new Mock<InterfaceA>(MockBehavior.Default); mock.As<InterfaceB>(); return mock.Object; } return new NoSpecimen(); } } }
2. 编写测试方法
使用自定义属性标记参数,AutoFixture会自动注入符合要求的模拟对象,再通过Moq操作模拟实例:
using AutoFixture.Xunit2; using Moq; using Xunit; public class MyClassTests { [Theory, AutoMoqData] public void MyMethod_WhenThingImplementsInterfaceB_ReturnsMethodOnBResult( [MockBothInterfaces] InterfaceA thing, MyType expectedResult) { // 获取模拟对象的InterfaceB实例 var bThingMock = Mock.Get(thing).As<InterfaceB>(); // 设置MethodOnB的返回值 bThingMock.Setup(b => b.MethodOnB()).Returns(expectedResult); // 初始化待测试类 var sut = new MyClass(thing); // 执行测试方法 var result = sut.MyMethod(); // 验证结果与调用情况 Assert.Equal(expectedResult, result); bThingMock.Verify(b => b.MethodOnB(), Times.Once); } }
关键说明
- 自定义属性通过
ISpecimenBuilder告知AutoFixture,生成InterfaceA对象时自动附加InterfaceB的模拟实现。 AutoMoqData属性启用AutoFixture与Moq的集成,保障模拟对象的正确注入。- 通过
Mock.Get(thing).As<InterfaceB>()可以获取到模拟对象的InterfaceB接口实例,用于设置返回值或验证调用行为。
内容的提问来源于stack exchange,提问作者Rob Mosher
相关产品推荐
相关产品推荐

