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

如何通过AutoFixture Attributes获取FakeTimeProvider引用以避免类型转换

问题:如何避免测试中每次强制转换FakeTimeProvider的操作?

我有一个依赖TimeProvider的Service类,目前用AutoFixture和Moq配置FakeTimeProvider的方式如下:

public class FakeTimeProviderCustomization : ICustomization {
    public void Customize(IFixture fixture) {
        fixture.Customize<TimeProvider>(c => c.FromFactory(() => new FakeTimeProvider()));
    }
}

public class MoqAutoDataAttribute : AutoDataAttribute {
    public MoqAutoDataAttribute()
        : base(() => new Fixture()
        .Customize(new AutoMoqCustomization())
        .Customize(new FakeTimeProviderCustomization())
        ) {
    }
}

[Theory, MoqAutoData]
public async Task Test_TimeRelatedStuff(
    [Frozen] TimeProvider timeProvider,
    Service sut) {
    
    // ...
    var fakeTimeProvider = timeProvider as FakeTimeProvider;
    // ...
}

请问能否避免每次都需要将timeProvider强制转换为FakeTimeProvider的操作?


解决方案

当然可以,有几种简单方式能省去强制转换的步骤:

方法1:直接在测试方法中注入FakeTimeProvider并标记[Frozen]

修改测试方法的参数,直接声明FakeTimeProvider类型并加上[Frozen]特性,AutoFixture会自动复用你之前定制好的实例(因为已将TimeProvider的实现替换为FakeTimeProvider):

[Theory, MoqAutoData]
public async Task Test_TimeRelatedStuff(
    [Frozen] FakeTimeProvider fakeTimeProvider,
    Service sut) {
    
    // 直接使用fakeTimeProvider,无需转换
    fakeTimeProvider.SetUtcNow(DateTimeOffset.Parse("2024-01-01"));
    // ...
}

方法2:扩展Customization,让Fixture支持直接创建FakeTimeProvider

修改FakeTimeProviderCustomization,同时注册FakeTimeProvider的实例,确保Fixture能直接解析该类型:

public class FakeTimeProviderCustomization : ICustomization {
    public void Customize(IFixture fixture) {
        var fakeTimeProvider = new FakeTimeProvider();
        // 注册FakeTimeProvider实例,同时将其作为TimeProvider的实现
        fixture.Inject(fakeTimeProvider);
        fixture.Inject<TimeProvider>(fakeTimeProvider);
    }
}

这样在测试中无论是请求TimeProvider还是FakeTimeProvider,都会拿到同一个实例,测试方法里直接用FakeTimeProvider类型即可。

方法3:自定义专属的AutoData属性(可选)

如果需要更统一的配置,可以在自定义AutoData属性中直接完成FakeTimeProvider的注入,进一步简化测试代码:

public class MoqWithFakeTimeAutoDataAttribute : AutoDataAttribute {
    public MoqWithFakeTimeAutoDataAttribute()
        : base(() => {
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            var fakeTime = new FakeTimeProvider();
            fixture.Inject(fakeTime);
            fixture.Inject<TimeProvider>(fakeTime);
            return fixture;
        }) {
    }
}

然后测试方法直接用这个新属性:

[Theory, MoqWithFakeTimeAutoData]
public async Task Test_TimeRelatedStuff(
    FakeTimeProvider fakeTimeProvider,
    Service sut) {
    // 直接使用
    // ...
}

内容的提问来源于stack exchange,提问作者Ivan Petrov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:53:16