SpecFlowOSS / SpecFlow

#1 .NET BDD Framework. SpecFlow automates your testing & works with your existing code. Find Bugs before they happen. Behavior Driven Development helps developers, testers, and business representatives to get a better understanding of their collaboration
https://www.specflow.org/
Other
2.24k stars 754 forks source link

[ERROR] Circular dependency found! NUnit.Framework.Internal.TestExecutionContext (resolution path: NUnit.Framework.TestContext->NUnit.Framework.Internal.TestExecutionContext) #2223

Closed ApiRulez closed 3 years ago

ApiRulez commented 3 years ago

SpecFlow Version:

Used Test Runner

Version number: 3.5.8

Project Format of the SpecFlow project

.feature.cs files are generated using

Visual Studio Version

Enable SpecFlowSingleFileGenerator Custom Tool option in Visual Studio extension settings

Are the latest Visual Studio updates installed?

.NET Framework:

Test Execution Method:

<SpecFlow> Section in app.config or content of specflow.json

  <specFlow>
    <!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
    <!--<unitTestProvider name="NUnit" />-->
    <trace traceSuccessfulSteps="false" />
  </specFlow>

Issue Description

I have migrated over from using SpecFlow / Speflow.Nuit to Specflow.Runner. When i go to run the tests the following error is reported:

---------- Starting test run ---------- SpecFlow+Runner execution started SpecFlow+Runner 3.5.8 in Framework clr40 in x86 mode execution started TestAdapter Location: C:\Repo\solution\packages\SpecRun.Runner.3.5.8\tools\net461\TechTalk.SpecRun.VisualStudio.TestAdapter.dll Current UserName: '*', MachineName: '**' SpecRun: running tests in C:\Repo\solution\Source\soemthing\bin\iOs_11_iPhone_X\something.Specs.dll Output folder configured to "C:\Repo\solution\TestResults" (default) Profile: Log file path: C:\Repo\solution\TestResults\Unnamed project__2020-12-02T131852.log Checking activation Activated. Activation check completed Starting test run Discovering target: Default Discovering tests from assembly: C:\Repo\solution\Source*.Specs\bin\iOs_11_iPhone_X\something.Specs.dll Discovered tests from assembly: C:\Repo\solution\Source*****.Specs\bin\iOs_11_iPhone_X\something.Specs.dll Scenario: Contact Us Dealer required fields in Contact Us -> Failed on thread #0 [ERROR] Circular dependency found! NUnit.Framework.Internal.TestExecutionContext (resolution path: NUnit.Framework.TestContext->NUnit.Framework.Internal.TestExecutionContext) Scenario: Contact Us Dealer required fields in Contact Us -> Failed on thread #0 [ERROR] Circular dependency found! NUnit.Framework.Internal.TestExecutionContext (resolution path: NUnit.Framework.TestContext->NUnit.Framework.Internal.TestExecutionContext) Scenario: Contact Us Dealer required fields in Contact Us -> Failed on thread #0 [ERROR] Circular dependency found! NUnit.Framework.Internal.TestExecutionContext (resolution path: NUnit.Framework.TestContext->NUnit.Framework.Internal.TestExecutionContext) test run finished publishing test results test results published generating reports Starting external report generation process Result: tests executed with warnings Total: 0 Succeeded: 0 Ignored: 0 Pending: 0 Skipped: 0 Failed: 0

Execution Time: 00:00:00 Adding attachments to VSTest SpecFlow+Runner execution finished ========== Test run finished: 3 Tests run in 7.1 sec (0 Passed, 3 Failed, 0 Skipped) ==========

ApiRulez commented 3 years ago

Anyone know how to resolve this please?

ApiRulez commented 3 years ago

It is the following method:

 public static T Resolve<T>(this ScenarioContext scenarioContext)
        {
            var container = GetContainer(scenarioContext);

            return container.Resolve<T>();
        }

that throws the following stacktrace:

BoDi.ObjectContainerException: 'Circular dependency found! NUnit.Framework.Internal.TestExecutionContext (resolution path: NUnit.Framework.TestContext->NUnit.Framework.Internal.TestExecutionContext)'
SabotageAndi commented 3 years ago

@NewmanUser123 you want to resolve from the BoDi container a type, that is probably not registered there. Or are you registering the NUnit TestContext by your own?

ApiRulez commented 3 years ago

@SabotageAndi unfortunately i cannot answer that as i have inherited this project. Is there any specific file i can look at to help answer the above?

ApiRulez commented 3 years ago

Here is the class where the error is thrown:

using System;
using System.Collections.Generic;
using System.Linq;
using BoDi;
using TechTalk.SpecFlow;

namespace Project.Specs.Support.Frameworks.Specflow
{
    public static class Extensions
    {
        public static string[,] MapTableToStringArray(this Table table)
        {
            var strArr = new string[table.Rows.Count + 1, table.Header.Count];
            var header = table.Header.ToArray();

            for (var i = 0; i < header.Length; i++)
            {
                strArr[0, i] = header[i];
            }

            var row = 0;
            var column = 1;

            foreach (var tableRow in table.Rows)
            {
                foreach (var item in tableRow)
                {
                    strArr[column, row++] = item.Value;
                }

                column++;
                row = 0;
            }
            return strArr;
        }

        /// <summary>
        /// This method will return null if the given column key is not found in the table.
        /// </summary>
        /// <param name="table"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        public static string Find(this Table table, int row, string column)
        {
            return !table.ContainsColumn(column) ? null : table.Rows[row][column];
        }

        /// <summary>
        /// Maps all rows in the given column of the table using the mapper delegate.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <param name="columnName"></param>
        /// <param name="mapper"></param>
        /// <returns></returns>
        public static IList<T> MapColumn<T>(this Table table, string columnName, Func<string, T> mapper)
            => table.Rows.Select(tr => mapper(tr[columnName])).ToList();

        public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>
            (this Table table,
                Func<TableRow, TKey> keySelector,
                Func<TableRow, TValue> valueSelector)
            => table.Rows.ToDictionary(keySelector, valueSelector);

        public static void RegisterInstance<T>
            (this ScenarioContext scenarioContext, 
                T @object, 
                string name = null, 
                bool dispose = false) where T : class
        {
            var container = GetContainer(scenarioContext);

            container.RegisterInstanceAs(@object, name, dispose);
        }

        public static void RegisterInstance<T>
            (this FeatureContext featureContext, 
                T @object, 
                string name = null,
                bool dispose = false) where T : class
            => featureContext.FeatureContainer.RegisterInstanceAs(@object, name, dispose);

        public static T Resolve<T>(this ScenarioContext scenarioContext)
        {
            var container = GetContainer(scenarioContext);

            return container.Resolve<T>();
        }

        public static T Resolve<T>(this FeatureContext featureContext)
            => featureContext.FeatureContainer.Resolve<T>();

        private static IObjectContainer GetContainer(ScenarioContext scenarioContext)
        {
            var container = (IObjectContainer)scenarioContext.GetBindingInstance(typeof(IObjectContainer));

            return container;
        }

        internal static TagHelper HasTag(this ScenarioInfo scenarioInfo) => new TagHelper(scenarioInfo.Tags);
    }
}
SabotageAndi commented 3 years ago

You have somewhere a call Resolve<TestContext> and that is not working.

ApiRulez commented 3 years ago

@SabotageAndi That would be in here:

But am still unsure on how to resolve the issue. Sorry for being thick here

using removed.Specs.Support.Helpers;
using removed.Specs.PageObjects;
using removed.Specs.Support.Frameworks.Specflow;
using removed.Specs.Support.Types;
using NUnit.Framework;
using OpenQA.Selenium;
using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Bindings;
using removed.Specs.Support;

namespace removed.Support.ReportConfig
{
    [Binding]
    public class Hooks : StepsBase
    {
        public Hooks(FeatureContext featureContext, ScenarioContext scenarioContext) 
            : base(featureContext, scenarioContext) { }

        private FeatureInfo FeatureInfo => FeatureContext.FeatureInfo;
        private ScenarioInfo ScenarioInfo => ScenarioContext.ScenarioInfo;
        private TestContext TestContext => ScenarioContext.Resolve<TestContext>();
        private StepInstance StepInstance => ScenarioContext.StepContext.StepInfo.StepInstance;

        [AfterTestRun]
        public static void CloseTestReport()
        {
            TestReport.Current.AddEnvironmentInfo(new BrowserConfiguration(), GetBuildNumber());

            TestReport.Current.Flush();
        }

        [BeforeScenario]
        public void AddScenarioToFeature()
        {
            TestReport.Current.AddFeature(FeatureInfo.Title, FeatureInfo.Description, FeatureInfo.Tags)
                .AddScenario(TestContext.Test.Name, ScenarioInfo.Tags);
        }

        [BeforeStep]
        public void AddStepToScenario()
        {
            var step = TestReport.Current[FeatureInfo.Title][TestContext.Test.Name]
                .AddStep(StepInstance.StepDefinitionKeyword, StepInstance.Text);

            if (StepInstance.TableArgument != null) step.AddTable(StepInstance.TableArgument);
        }

        [AfterStep]
        public void LogTestStepOutcome()
        {
            Screenshot screenShot = null;

            if (ScenarioContext.TestError != null)
            {
                screenShot = TakeScreenShot();
            }

            TestReport.Current[FeatureInfo.Title][TestContext.Test.Name][StepInstance.Text]
                .LogTestOutcome(ScenarioContext.TestError, screenShot?.AsBase64EncodedString);

            TestReport.Current.Flush();
        }

        private Screenshot TakeScreenShot()
        {
            var browser = ScenarioContext.Resolve<Browser>();

            return browser?.TakeScreenShot();
        }

        private static string GetBuildNumber()
        {
            var siteBuildNumber = new SiteBuildNumber(Configuration.removed().removedBaseUrl);

            var tryGetBuildNumber = Exceptional.Execute(() => siteBuildNumber.Get());

            return tryGetBuildNumber.HasError ? "Not Available" : tryGetBuildNumber.Result;
        }
    }
}
SabotageAndi commented 3 years ago

Try to change it to this:


public Hooks(FeatureContext featureContext, ScenarioContext scenarioContext, TestContext testContext) 
            : base(featureContext, scenarioContext) {
        TestContext = testContext
 }

private TestContext TestContext { get; private set; }
ApiRulez commented 3 years ago

Hi @SabotageAndi ,

Have updated, but unfortunately, i still get a circular dependency. Can appreciate there maybe a multitude of reasons for this. I have updated this part of the above:

        [BeforeScenario]
        public void AddScenarioToFeature()
        {
            var context = new NUnit.Framework.Internal.TestExecutionContext();
            ScenarioContext.RegisterInstance(context);
            TestReport.Current.AddFeature(FeatureInfo.Title, FeatureInfo.Description, FeatureInfo.Tags)
                .AddScenario(TestContext.Test.Name, ScenarioInfo.Tags);
        }

Which gets round circle, but now i get object is not an instance on methods below

github-actions[bot] commented 3 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.