'BoDi.ObjectContainerException : Interface cannot be resolved in Specflow test

I have this step in a Specflow test:

[Then(@"the enriched messages are written to the LC")]
public void ThenTheEnrichedMessagesAreWrittenToTheLC()
{
    var LcApplicationOptions = new LcApplicationOptions();
    _configuration.GetSection("LcApplication").Bind(LcApplicationOptions);
    Subscription sub = new Subscription(LcApplicationOptions.LcVendor, LcApplicationOptions.LcInstrument);
    MessageConsumer consumer = new NetMessageConsumer();
    // If Client throws an exception via ctor then it probably cant find Config\Fields.json
    using (Client c = new Client(LcApplicationOptions.LcHost, _loggerClient, _fieldDictionary, _subscriptionIdGenerator, _iLifetimeScope))
    {
        int subscriptionId;

        c.OnConnected += Client_OnConnected;
        c.OnClosed += Client_OnClosed;

        // Register the subscription which will connect to LC and login first.
        // Any updates for this instrument will be handled by "consumer".
        subscriptionId = c.Register(sub, LcApplicationOptions.LcAuthToken, consumer);

        // The subscriptionId is also reflected in sub.Id after the call.
        Console.WriteLine("hit enter...");
        //Console.ReadLine();

        // You can unsubscribe like this
        c.Unregister(sub.Id);
    }
}

When I ran it I got this error:

[xUnit.net 00:02:31.22] System.ArgumentNullException : Value cannot be null. (Parameter 'logger') [xUnit.net 00:02:31.22] Stack Trace: [xUnit.net 00:02:31.22] at Microsoft.Extensions.Logging.LoggerExtensions.Log(ILogger logger, LogLevel logLevel, EventId eventId, Exception exception, String message, Object[] args) [xUnit.net 00:02:31.22] at Microsoft.Extensions.Logging.LoggerExtensions.Log(ILogger logger, LogLevel logLevel, Exception exception, String message, Object[] args) [xUnit.net 00:02:31.22] at Microsoft.Extensions.Logging.LoggerExtensions.LogError(ILogger logger, Exception exception, String message, Object[] args) [xUnit.net 00:02:31.22] at NX.Data.Client.AddRequest(Subscription sub, ConsumerInfo ci, IMessageConsumer msgConsumer) [xUnit.net 00:02:31.22] at NX.Data.Client.Register(Subscription sub, String authToken, IMessageConsumer msgConsumer) [xUnit.net 00:02:31.22]

The problem is that the Client constructor is as follows but I was passing a null for logger.

public Client(string lcClientAddress, ILogger<Client> logger, IFieldDictionary fieldDictionary, SubscriptionIdGenerator subscriptionIdGenerator, ILifetimeScope scope);

I edited my steps class constructor as follows:

private readonly ILogger<Client> _loggerClient;

public EBSIntegrationTestStepDefinitions(ITestOutputHelper testOutputHelper, ScenarioContext scenarioContext, FeatureContext featureContext, ILogger<Client> loggerClient)
{
    _loggerClient = loggerClient;
}

Now when I run my test I get this:

xUnit.net 00:00:01.08] BoDi.ObjectContainerException : Interface cannot be resolved: Microsoft.Extensions.Logging.ILogger1[[NX.Data.Client, DpNet.Data, Version=0.0.2.178, Culture=neutral, PublicKeyToken=null]] (resolution path: ebs_test_tool.Steps.EBSIntegrationTestStepDefinitions) [xUnit.net 00:00:01.08] Stack Trace: [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.TypeRegistration.<>c__DisplayClass3_0.<ResolvePerContext>b__1() [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.RegistrationWithStrategy.ExecuteWithLock(Object lockObject, Func1 getter, Func1 factory, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.TypeRegistration.ResolvePerContext(ObjectContainer container, RegistrationKey keyToResolve, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.RegistrationWithStrategy.Resolve(ObjectContainer container, RegistrationKey keyToResolve, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.ResolveObject(RegistrationKey keyToResolve, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.Resolve(Type typeToResolve, ResolutionList resolutionPath, String name) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.<>c__DisplayClass71_0.<ResolveArguments>b__0(ParameterInfo p) [xUnit.net 00:00:01.08] at System.Linq.Enumerable.SelectArrayIterator2.ToArray() [xUnit.net 00:00:01.08] at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.ResolveArguments(IEnumerable1 parameters, RegistrationKey keyToResolve, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.CreateObject(Type type, ResolutionList resolutionPath, RegistrationKey keyToResolve) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.TypeRegistration.<>c__DisplayClass3_0.b__1() [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.RegistrationWithStrategy.ExecuteWithLock(Object lockObject, Func1 getter, Func1 factory, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.TypeRegistration.ResolvePerContext(ObjectContainer container, RegistrationKey keyToResolve, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.RegistrationWithStrategy.Resolve(ObjectContainer container, RegistrationKey keyToResolve, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.ResolveObject(RegistrationKey keyToResolve, ResolutionList resolutionPath) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.Resolve(Type typeToResolve, ResolutionList resolutionPath, String name) [xUnit.net 00:00:01.08] at BoDi.ObjectContainer.Resolve(Type typeToResolve, String name) [xUnit.net 00:00:01.08] at TechTalk.SpecFlow.Infrastructure.TestObjectResolver.ResolveBindingInstance(Type bindingType, IObjectContainer container) [xUnit.net 00:00:01.08] at lambda_method(Closure , IContextManager , String , String ) [xUnit.net 00:00:01.08] at TechTalk.SpecFlow.Bindings.BindingInvoker.InvokeBinding(IBinding binding, IContextManager contextManager, Object[] arguments, ITestTracer testTracer, TimeSpan& duration) [xUnit.net 00:00:01.08] at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStepMatch(BindingMatch match, Object[] arguments, TimeSpan& duration) [xUnit.net 00:00:01.08] at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStep(IContextManager contextManager, StepInstance stepInstance) [xUnit.net 00:00:01.08] at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.OnAfterLastStep() [xUnit.net 00:00:01.08] at TechTalk.SpecFlow.TestRunner.CollectScenarioErrors() [xUnit.net 00:00:01.08] at ebs_test_tool.Features.EBSIntegrationTestFeature.ScenarioCleanup() [xUnit.net 00:00:01.08]

I also noticed this in my output:

[xUnit.net 00:00:01.09] Output: [xUnit.net 00:00:01.09] Given MRF application "Eb.MarketFeed.Fx" runs version "0.1.52" [xUnit.net 00:00:01.09] -> error: Interface cannot be resolved: Microsoft.Extensions.Logging.ILogger`1[NX.Data.Client, DpNet.Data, Version=0.0.2.178, Culture=neutral, PublicKeyToken=null]] (resolution path: eb_test_tool.Steps.IntegrationTestStepDefinitions) (0.0s)

Previously when I got a similar error I had to add [Binding] to my class but I already have it.

I'm wondering if this is indeed a binding issue or if it's just that I'm trying to pass ILogger<Client> is a class that isn't Client. How do I resolve this?



Solution 1:[1]

You will need to register an ILogger<Client> object in the SpecFlow IoC container. This should be done in a "BeforeScenario" hook:

[Binding]
public class SpecFlowHooks
{
    public SpecFlowHooks(IObjectContainer container)
    {
        this.container = container;
    }

    [BeforeScenario]
    public void CreateLogger()
    {
        ILogger<Client> logger = // initialize client logger here

        container.RegisterInstanceAs(logger);
    }
}

If you do not do this, the IoC container that initializes new instances of your step definitions will not know how to resolve the ILogger<Client> interface, which results in the exception you reported.

Solution 2:[2]

To add more clarifiaction to Greg Burghardt's answer, you can write a static class that would help you get the instance of the logger with a specific type

[Binding]
public class SpecFlowHooks
{
    private readonly IObjectContainer _container;
    public SpecFlowHooks(IObjectContainer container)
    {
        _container = container;
    }

    [BeforeScenario]
    public void CreateLogger()
    {
        var logger = LoggerDriver.GetLogger<Client>();
        _container.RegisterInstanceAs(logger);
    }
}

public static class LoggerDriver
{
    public static ILogger<T> GetLogger<T>() where T : class
    {
        ILogger<T> logger = new LoggerFactory().CreateLogger<T>();
        return logger;
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Greg Burghardt
Solution 2 Zwelithini.Mphanza