solidtoken / SpecFlow.DependencyInjection

SpecFlow plugin that enables to use Microsoft.Extensions.DependencyInjection for resolving test dependencies.
BSD 3-Clause "New" or "Revised" License
35 stars 11 forks source link

System.NullReferenceException inside TechTalk.SpecFlow #24

Closed 304NotModified closed 4 years ago

304NotModified commented 4 years ago

Hi,

I added this to my specflow project:

    <PackageReference Include="SpecFlow" Version="3.1.80" />
    <PackageReference Include="SpecFlow.MsTest" Version="3.1.80" />
    <PackageReference Include="SpecFlow.Tools.MsBuild.Generation" Version="3.1.80" />
    <PackageReference Include="SolidToken.SpecFlow.DependencyInjection" Version="0.3.2" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
    <PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
    <PackageReference Include="MSTest.TestFramework" Version="2.0.0" />

and

    public class SpecflowHooks
    {

        [ScenarioDependencies]
        public static IServiceCollection CreateServices()
        {
            var services = new ServiceCollection();
            return services;
        }
    }

And now I get for all tests:

System.NullReferenceException: Object reference not set to an instance of an object.
    at lambda_method(Closure , IContextManager , String )
   at TechTalk.SpecFlow.Bindings.BindingInvoker.InvokeBinding(IBinding binding, IContextManager contextManager, Object[] arguments, ITestTracer testTracer, TimeSpan& duration) in D:\a\1\s\TechTalk.SpecFlow\Bindings\BindingInvoker.cs:line 69
   at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStepMatch(BindingMatch match, Object[] arguments) in D:\a\1\s\TechTalk.SpecFlow\Infrastructure\TestExecutionEngine.cs:line 501
   at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStep(IContextManager contextManager, StepInstance stepInstance) in D:\a\1\s\TechTalk.SpecFlow\Infrastructure\TestExecutionEngine.cs:line 422
   at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.Step(StepDefinitionKeyword stepDefinitionKeyword, String keyword, String text, String multilineTextArg, Table tableArg) in D:\a\1\s\TechTalk.SpecFlow\Infrastructure\TestExecutionEngine.cs:line 581
   at TechTalk.SpecFlow.TestRunner.Given(String text, String multilineTextArg, Table tableArg, String keyword) in D:\a\1\s\TechTalk.SpecFlow\TestRunner.cs:line 80
   at 

any idea?

Update: same issue with 0.3.1 and 0.2.4. What am I missing?

mbhoek commented 4 years ago

Let me investigate and I will get back to you.

304NotModified commented 4 years ago

FYI:

 <TargetFramework>netcoreapp2.1</TargetFramework>

tried also static class, but that won't help either.

The big difference is here (I think), that we're using MSTest and not xUnit

304NotModified commented 4 years ago

I found the issue (I have checked out the repo)

If the dependency isn't found, you will get this nasty exception.

So:

namespace SolidToken.SpecFlow.DependencyInjection.Tests
{
    public static class TestDependencies
    {
        [ScenarioDependencies]
        public static IServiceCollection CreateServices()
        {
            var services = new ServiceCollection();

            //// Add test dependencies
            //services.AddTransient<ITestService, TestService>();

            //// ContextInjectionScope (by using AddScoped instead of AddTransient, the context will be scoped to the Feature across bindings)
            //services.AddScoped<TestContext>();

            //// NOTE: This line is essential so that Microsoft.Extensions.DependencyInjection knows
            //// about the SpecFlow bindings (something normally BoDi does automatically).
            //// TODO: Find out if we can make this part of the Plugin
            //foreach (var type in typeof(TestDependencies).Assembly.GetTypes().Where(t => Attribute.IsDefined(t, typeof(BindingAttribute))))
            //{
            //    services.AddSingleton(type);
            //}

            return services;
        }
    }
}

Will demo the issue

mbhoek commented 4 years ago

Is it possible that you have not registered any bindings (yet)?

For example, if you look at DependencyInjectionPluginSteps.cs you will notice the [Binding] tag that will bind the code to the SpecFlow Feature file.

Currently the plugin requires you to register all the bindings/step definitions (otherwise the DI framework can't find them). So your initialisation code should look like:

  var services = new ServiceCollection();

  foreach (var type in typeof(TestDependencies).Assembly.GetTypes().Where(t => Attribute.IsDefined(t, typeof(BindingAttribute))))
  {
      services.AddSingleton(type);
  }

  return services;

Although this is in the README.md, I don't think it is very intuitive and I want to solve it as part of issue #7 but haven't landed on a solution yet.

304NotModified commented 4 years ago

ow yes indeed. I missed that! That's the fix.

Would be great if we could make that optional.

304NotModified commented 4 years ago

@mbhoek check https://github.com/solidtoken/SpecFlow.DependencyInjection/pull/25 :)

This could be closed.