`ObjectContainer.IsRegistered<T>()` does not walk up the inheritance chain, even though `Resolve<T>()` does, giving misleading results
SpecFlow Version
3.9.74
Which test runner are you using?
xUnit
Test Runner Version Number
2.4.1
.NET Implementation
.NET 8.0
Project Format of the SpecFlow project
Sdk-style project format
.feature.cs files are generated using
SpecFlow.Tools.MsBuild.Generation NuGet package
Test Execution Method
Visual Studio Test Explorer
SpecFlow Section in app.config or content of specflow.json
{ "$schema": "https://specflow.org/specflow-config.json", "stepAssemblies": [ { "assembly": "<my_common_assembly>" } ] }
Issue Description
I am registering services in the Global container in a [BeforeTestRun] method due to Issue #2580.
[BeforeTestRun(Order = 10)]
public static void SetEnvironmentConfiguration(ObjectContainer container)
{
// Registering to the base container is necessary due to an integration issue with XUnit:
// https://github.com/SpecFlowOSS/SpecFlow/issues/2580
container.BaseContainer.RegisterInstanceAs<IEnvironmentConstantsProvider>(EnvironmentConstants.Instance);
}
In another portion of my project, I am attempting to proactively check whether this dependency has been registered so I can give a helpful error message:
if (!container.IsRegistered<IEnvironmentConstantsProvider>())
{
throw new Exception($"{nameof(IEnvironmentConstantsProvider)} not registered in container. See <docs_on_how_to_configure_correctly>");
}
var envProvider = container.Resolve<IEnvironmentConstantsProvider>();
This call to IsRegistered() is returning false, even though the object is registered, just not at the hierarchy level of the current ObjectContainer... If I comment out my if check, the object resolves as expected because Resolve() actually walks up the inheritance chain to find an object. But it seems as if IsRegistered() simply stops and returns false if it isn't in the immediate scope of the current ObjectContainer - which is not what I'd expect as a user.
NOTE: I've devised a workaround by introducing an extension method as follows, which works:
public static bool IsRegisteredAtAnyLevel<T>(this IObjectContainer container)
{
do
{
if (container.IsRegistered<T>())
{
return true;
}
} while (container is ObjectContainer c && (container = c.BaseContainer) != null);
return false;
}
Steps to Reproduce
- Register an object at the
TestThreadorFeaturelevel. - Call
container.IsRegistered<MyObj>()at the scenario level => FAIL - Call
container.Resolve<MyObj>()at the scenario level => SUCCESS
My issue description also provides a decent description of the repro.
Link to Repro Project
Closed source project