jguc / SpecFlow.SimpleInjector

SpecFlow plugin for using SimpleInjector as a dependency injection framework for step definitions
Apache License 2.0
2 stars 5 forks source link

Error when injecting ScenarioContext in .NET Framework 4.8 #12

Open grootstebozewolf opened 3 years ago

grootstebozewolf commented 3 years ago

Steps to reproduce

Create a .Net Framework test project (MSBuild)

Added the following packages:
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="BoDi" version="1.4.1" targetFramework="net48" />
  <package id="Cucumber.Messages" version="6.0.1" targetFramework="net48" />
  <package id="Gherkin" version="6.0.0" targetFramework="net48" />
  <package id="Google.Protobuf" version="3.7.0" targetFramework="net48" />
  <package id="MSTest.TestAdapter" version="2.1.2" targetFramework="net48" />
  <package id="MSTest.TestFramework" version="2.1.2" targetFramework="net48" />
  <package id="SimpleInjector" version="5.3.0" targetFramework="net48" />
  <package id="SpecFlow" version="3.1.80" targetFramework="net48" />
  <package id="SpecFlow.MsTest" version="3.1.80" targetFramework="net48" />
  <package id="SpecFlow.SimpleInjector" version="2.0.0" targetFramework="net48" />
  <package id="SpecFlow.Tools.MsBuild.Generation" version="3.1.80" targetFramework="net48" />
  <package id="System.IO" version="4.3.0" targetFramework="net48" />
  <package id="System.Net.Http" version="4.3.4" targetFramework="net48" />
  <package id="System.Reflection.Emit" version="4.3.0" targetFramework="net48" />
  <package id="System.Reflection.Emit.Lightweight" version="4.3.0" targetFramework="net48" />
  <package id="System.Runtime" version="4.3.0" targetFramework="net48" />
  <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net48" />
  <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net48" />
  <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net48" />
  <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net48" />
  <package id="System.Threading.Tasks.Extensions" version="4.4.0" targetFramework="net48" />
  <package id="System.ValueTuple" version="4.4.0" targetFramework="net48" />
  <package id="Utf8Json" version="1.3.7" targetFramework="net48" />
</packages>

Ammended the app.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="BoDi" publicKeyToken="ff7cd5ea2744b496" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.4.0.0" newVersion="1.4.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="SimpleInjector" publicKeyToken="984cb50dea722e99" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Created a simple test feature file and implemented the steps, then created a step implementation where I inject the scenarioContext:

using System;
using TechTalk.SpecFlow;

namespace Example
{
    [Binding]
    public class ExampleSteps
    {
        private readonly ScenarioContext scenarioContext;

        public PermissiesSteps(ScenarioContext scenarioContext)
        {
            this.scenarioContext = scenarioContext;
        }

        [Given(@"some given step")]
        public void SomeGivenStep()
        {
            scenarioContext.Pending();
        }        
    }
}

Bound the container in a TestDependencies support class

using SimpleInjector;
using SpecFlow.SimpleInjector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Example
{
    public static class TestDependencies
    {
        [ScenarioDependencies]
        public static Container CreateContainerBuilder()
        {
            // create empty container
            var builder = new Container();

            //TODO: add customizations, stubs required for testing

            return builder;
        }
    }
}
grootstebozewolf commented 3 years ago

Error:

Message: 
    Test method Example.Features.SomeGivenStep threw exception: 
    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingFieldException: Field not found: 'SimpleInjector.Lifestyle.Singleton'.
  Stack Trace: 
    SimpleInjectorPlugin.RegisterSpecFlowDependencies(IObjectContainer objectContainer, Container container)
    <>c__DisplayClass1_0.<Initialize>b__2()
    --- End of inner exception stack trace ---
    RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
    RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
    Delegate.DynamicInvokeImpl(Object[] args)
    ObjectContainer.InvokeFactoryDelegate(Delegate factoryDelegate, ResolutionList resolutionPath, RegistrationKey keyToResolve) line 827
    FactoryRegistration.Resolve(ObjectContainer container, RegistrationKey keyToResolve, ResolutionList resolutionPath) line 411
    ObjectContainer.ResolveObject(RegistrationKey keyToResolve, ResolutionList resolutionPath) line 779
    ObjectContainer.Resolve(Type typeToResolve, ResolutionList resolutionPath, String name) line 698
    ObjectContainer.Resolve[T](String name) line 673
    ObjectContainer.Resolve[T]() line 666
    SimpleInjectorTestObjectResolver.ResolveBindingInstance(Type bindingType, IObjectContainer scenarioContainer)
    lambda_method(Closure , IContextManager )
    BindingInvoker.InvokeBinding(IBinding binding, IContextManager contextManager, Object[] arguments, ITestTracer testTracer, TimeSpan& duration) line 69
    TestExecutionEngine.ExecuteStepMatch(BindingMatch match, Object[] arguments) line 517
    TestExecutionEngine.ExecuteStep(IContextManager contextManager, StepInstance stepInstance) line 422
    TestExecutionEngine.OnAfterLastStep() line 203
    TestRunner.CollectScenarioErrors() line 59
    ExampleFeature.ScenarioCleanup()
    ExampleFeature.SomeGivenStep() line 6
grootstebozewolf commented 3 years ago

Tried to upgrade to the latest versions of SpecFlow and SimpleInjector.

Ammended the Example project

using SimpleInjector;
using SpecFlow.SimpleInjector;

namespace MyCalculator.Specs.Support
{
    public static class TestDependencies
    {
        [ScenarioDependencies]
        public static Container CreateContainerBuilder()
        {
            // create container with the runtime dependencies
            var builder = Dependencies.CreateContainerBuilder();
            builder.Options.ResolveUnregisteredConcreteTypes = true;

            //TODO: add customizations, stubs required for testing

            return builder;
        }
    }
}

After this, the teardown gave this error:

 AddTwoNumbers
   Source: Addition.feature line 7
   Duration: 2 min

  Message: 
    TestCleanup method MyCalculator.Specs.Features.AdditionFeature.TestTearDown threw exception. System.InvalidOperationException: System.InvalidOperationException: Collection was modified; enumeration operation may not execute..
  Stack Trace: 
    ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
    Enumerator.MoveNext()
    <OfTypeIterator>d__95`1.MoveNext()
    WhereEnumerableIterator`1.MoveNext()
    ObjectContainer.Dispose()
    InternalContextManager`1.DisposeInstance()
    InternalContextManager`1.Cleanup()
    ContextManager.CleanupScenarioContext()
    TestExecutionEngine.OnScenarioEnd()
    TestRunner.OnScenarioEnd()
    AdditionFeature.TestTearDown()

And additional info:

-> Loading plugin C:\Users\_behbloemscheerj\Source\Repos\SpecFlow.SimpleInjector\sample\MyCalculator\MyCalculator.Specs\bin\Debug\net48\SpecFlow.SimpleInjector.SpecFlowPlugin.dll
-> Loading plugin C:\Users\_behbloemscheerj\Source\Repos\SpecFlow.SimpleInjector\sample\MyCalculator\MyCalculator.Specs\bin\Debug\net48\TechTalk.SpecFlow.MSTest.SpecFlowPlugin.dll
-> Loading plugin C:\Users\_behbloemscheerj\Source\Repos\SpecFlow.SimpleInjector\sample\MyCalculator\MyCalculator.Specs\bin\Debug\net48\MyCalculator.Specs.dll
-> Missing [assembly:RuntimePlugin] attribute in MyCalculator.Specs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null. Please check https://go.specflow.org/doc-plugins for details.
-> Using specflow.json
Given I have entered 50 into the calculator
-> done: CalculatorSteps.GivenIHaveEnteredIntoTheCalculator(50) (0.4s)
And I have entered 70 into the calculator
-> done: CalculatorSteps.GivenIHaveEnteredIntoTheCalculator(70) (0.0s)
When I press add
-> done: CalculatorSteps.WhenIPressAdd() (0.0s)
Then the result should be 120 on the screen
-> done: CalculatorSteps.ThenTheResultShouldBeOnTheScreen(120) (72.7s)