You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 07:35:21