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

AutoFixture集成BUnit进行Blazor测试时,注入object类型服务无法返回已注册实例的问题

Why Your MockServiceProvider's RegisterServices Method Isn't Reusing Injected Instances

你推测的原因完全正确——问题出在AutoFixture.Inject方法的重载行为上,而非你传入实例的方式。让我们一步步拆解:

The Root Cause: AutoFixture's Inject Overloads

AutoFixture提供了两个关键的Inject重载:

  1. 泛型重载: public void Inject<T>(T instance)
    这个重载会把instance注册为**类型T**的唯一实例。当你请求T类型的对象时,AutoFixture会直接返回这个注入的实例。
  2. 非泛型重载: public void Inject(object instance)
    这个重载只会把instance注册为**类型object**的实例,而不是它的实际运行时类型。

在你的RegisterServices方法中,serviceInstance是object类型,所以编译器会绑定到非泛型的Inject(object)重载。这意味着你注入的实例只会被关联到object类型,而不会关联到它们实际实现的接口(比如IMyFirstService)。当你调用GetService(typeof(IMyFirstService))时,AutoFixture找不到针对IMyFirstService的注入实例,就会创建一个新的实例。

Why dynamic Doesn't Fix It

使用params dynamic[]也不会解决问题,因为C#的动态绑定在编译时仍然会选择最匹配的重载——这里还是会选中Inject(object),因为dynamic变量在编译阶段的静态类型还是object。

Solutions

1. Use the Generic RegisterService<T> Method (Your Current Fix)

你已经发现的泛型方法是最直接的解决方案,因为它明确调用了Inject<T>重载,把实例注册为正确的类型:

public void RegisterService<T>(T serviceInstance) { 
    this.fixture.Inject(serviceInstance); 
}

2. Add a Batch Registration Method Using Reflection

如果你想保持批量注册的便利性,可以通过反射调用泛型的Inject方法,自动获取每个实例的实际类型:

public void RegisterServices(params object[] serviceInstances) { 
    foreach (var serviceInstance in serviceInstances) {
        var injectMethod = typeof(Fixture).GetMethod(nameof(Fixture.Inject))!
            .MakeGenericMethod(serviceInstance.GetType());
        injectMethod.Invoke(this.fixture, new[] { serviceInstance });
    } 
}

这个方法会为每个实例找到对应的泛型Inject<T>重载,并调用它,确保实例被注册为其实际的运行时类型。

Testing the Fix

修改后,当你调用serviceProvider.RegisterServices(firstService, secondService),AutoFixture会将这些实例分别注册为IMyFirstService和IMySecondService类型。后续调用GetService请求这些类型时,就会返回你注入的实例,而不是创建新的。

内容的提问来源于stack exchange,提问作者Ben Rubin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 14:37:45