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

NSubstitute参数匹配时Returns被忽略问题排查

Troubleshooting Your NSubstitute Mock Not Returning Expected Value

Let's break down why your mocked ILicenseChecker.IsEnabled isn't returning the expected enabled value, and how to fix it:

1. Your DI Container Might Not Be Injecting the Mocked License Checker

The most likely culprit here is that MApplication.Container.Resolve<IEntityDefinitionQuerying> isn't actually using the mocked licenseChecker you passed via TypedParameter. Many DI containers prioritize pre-registered instances over inline parameters, so if your container already has a registered implementation of ILicenseChecker, it'll ignore your substituted instance.

How to Verify & Fix:

  • Debug Check: After resolving querying, inspect its internal ILicenseChecker field (via debugger or reflection) to confirm it's the substitute you created.
  • Temporary Registration Override: Instead of relying on TypedParameter, temporarily replace the container's registered ILicenseChecker with your mock:
    public async Task<T> QuerySingleDefinition<T>(Func<IEntityDefinitionQuerying, EntityDefinition, Task<T>> target, bool enabled)
    {
        var definition = await CreateDefinition().ConfigureAwait(false);
    
        var licenseChecker = Substitute.For<ILicenseChecker>();
        licenseChecker.IsEnabled(Arg.Is<EntityDefinition>(p => p.Id == definition.Id), Arg.Any<User>()).Returns(Task.FromResult(enabled));
    
        // Save original registration to restore later
        var originalRegistration = MApplication.Container.GetRegistration(typeof(ILicenseChecker));
        try
        {
            // Register the mock as the current instance
            MApplication.Container.RegisterInstance(licenseChecker);
            var querying = MApplication.Container.Resolve<IEntityDefinitionQuerying>();
    
            return await target(querying, definition).ConfigureAwait(false);
        }
        finally
        {
            // Restore original registration to avoid breaking other tests
            if (originalRegistration != null)
            {
                MApplication.Container.Register(originalRegistration);
            }
            else
            {
                MApplication.Container.Unregister(typeof(ILicenseChecker));
            }
        }
    }
    

2. Your Argument Matching Condition Isn't Being Met

Even if the mock is injected correctly, the Arg.Is<EntityDefinition>(p => p.Id == definition.Id) condition might not be triggering. This could happen if:

  • The EntityDefinition passed to IsEnabled in your target delegate is a different instance (e.g., cloned or reloaded) with the same Id (though the Id check should still work if it's a value type like Guid or int).
  • The definition.Id value changed between when you created the mock and when IsEnabled is called.
  • You're dealing with a reference-type Id (like a custom class) where equality isn't properly implemented.

How to Verify & Fix:

  • Log or Debug the Parameters: Add a callback to your mock to inspect the actual parameters being passed:
    licenseChecker.When(x => x.IsEnabled(Arg.Any<EntityDefinition>(), Arg.Any<User>()))
                  .Do(call => 
                  {
                      var passedDef = call.Arg<EntityDefinition>();
                      // Compare passedDef.Id to definition.Id here (debug or log)
                  });
    
  • Simplify the Match: If the Id is a value type, you can bypass the object check and match directly on the Id (if IsEnabled has an overload that accepts the Id instead of the full EntityDefinition):
    licenseChecker.IsEnabled(definition.Id, Arg.Any<User>()).Returns(Task.FromResult(enabled));
    

3. Method Signature Mismatch

Double-check that the IsEnabled method signature you're mocking exactly matches what's being called in target. For example:

  • Are the parameter types correct? (Is the second parameter really User, or a derived type?)
  • Are there overloads of IsEnabled that you're not accounting for? If target calls a different overload, your mock configuration won't apply.

How to Verify & Fix:

  • Check the ILicenseChecker interface definition to confirm the exact signature of IsEnabled.
  • If overloads exist, explicitly specify parameter types in your mock setup to avoid ambiguity:
    licenseChecker.IsEnabled(Arg.Is<EntityDefinition>(p => p.Id == definition.Id), Arg.Any<User>())
                  .Returns(Task.FromResult(enabled));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 17:01:49