Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In SpecFlow 2.2.1, how do I access the MsTest TestContext? #936

Closed
CharlieMott opened this issue Sep 14, 2017 · 27 comments
Closed

In SpecFlow 2.2.1, how do I access the MsTest TestContext? #936

CharlieMott opened this issue Sep 14, 2017 · 27 comments

Comments

@CharlieMott
Copy link

We were using this partial class technique (https://stackoverflow.com/a/16891022) to hold the Microsoft.VisualStudio.TestTools.UnitTesting.TestContext in the TechTalk.SpecFlow.FeatureContext.

I have just upgraded to specflow 2.2.1. The test projects with features using this technique no longer compile as we have two TextContext properties (one in the generated feature.cs code and one in our custom partial file). This was introduced into 2.2.1 as part of the pull request #882. Looking at the Specflow generated feature.cs file I see the following generated code.

public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) { testRunner.OnScenarioStart(scenarioInfo); testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs<Microsoft.VisualStudio.TestTools.UnitTesting.TestContext>(TestContext); }

But How do I now access the TestContext from my code?

After removing the custom partial class, when debugging my updated BeforeScenario hook code and from a Step Definition, I see the following:

  • FeatureContext.Current.Count = 0
  • ScenarioContext.Current.Count = 0

--
SpecFlow Version: 2.2.1
Test Runner: MSTest
Visual Studio Version: 2013
.NET Framework: >= .NET 4

@SabotageAndi
Copy link
Contributor

Do you have access to the TestContext in a normal binding?

@SabotageAndi
Copy link
Contributor

BTW, *Context.Current.Count is looking into the context dictionary for values, these are not the container registrations.

You can get it from the container directly:

ScenarioContext.Current.ScenarioContainer.Resolve<Microsoft.VisualStudio.TestTools.UnitTesting.TestContext>()

or via context injection:

public class MyStepDefs
{
    private readonly TestContext _testContext;
    public MyStepDefs(TestContext testContext) // use it as ctor parameter
    { 
        _testContext = testContext;
    }

    [BeforeScenario()]
    public void BeforeScenario()
    {
        //now you can access the TestContext
    } 
}

@CharlieMott
Copy link
Author

So the following does indeed work within a Test Definition method.

[Given(@"my test step definition")]
public void MyStepDefinition()
{
   var testContext = ScenarioContext.Current.ScenarioContainer.Resolve<Microsoft.VisualStudio.TestTools.UnitTesting.TestContext>();
   var environmentName = testContext.Properties["environmentName"];
}

But it is not working from within my scoped hook.

[BeforeScenario("MyHookScope")]
public void BeforeScenario()
{
   var testContext = ScenarioContext.Current.ScenarioContainer.Resolve<Microsoft.VisualStudio.TestTools.UnitTesting.TestContext>();
}

I get an exception: "Cannot create an instance of Microsoft.VisualStudio.TestTools.UnitTesting.TestContext because it is an abstract class."

@SabotageAndi
Copy link
Contributor

ok, you get the exception because the class is not registered.
Could you post a sample project somewhere? or at least the code behind file of one of your feature files?

@CharlieMott
Copy link
Author

Thanks for you help on this. I've uploaded a sample project here:
https://1drv.ms/u/s!AqwhWEb4PipXgdgSQw4N3_uWXpXuXw
The "RunTestWithAHook" scenario is currently failing.

@SabotageAndi
Copy link
Contributor

I found the issue. Look at the generated code of the ScenarioSetup method:

public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
{
    testRunner.OnScenarioStart(scenarioInfo);
    testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs<Microsoft.VisualStudio.TestTools.UnitTesting.TestContext>(TestContext);
}

The TestContext is registered in the ScenarioContainer after the OnScenarioStart call. Which is necessary, as the ScenarioContainer is created within this call.
But also the BeforeScenario Hook is fired in this method.
So we have a chicken- egg- problem here.

@gasparnagy Any idea how to fix this?

@gasparnagy
Copy link
Contributor

@SabotageAndi a solution could be to extend the OnScenarioStart to accept a delegate that would be called after the context is created but before the hooks are executed.

@CharlieMott a workaround for you could be to use a "BeforeStep" hook and remember if it was called:

private bool isInvoked = false;
[BeforeStep("MyHookScope")]
public void BeforeScenario()
{
    if (isInvoked) return;
    isInvoked = true;
   var testContext = ScenarioContext.Current.ScenarioContainer.Resolve<Microsoft.VisualStudio.TestTools.UnitTesting.TestContext>();
}

@CharlieMott
Copy link
Author

Thanks @gasparnagy , this workaround does indeed work for my needs.

@JasonArm
Copy link

JasonArm commented Oct 17, 2017

Using Specflow 2.2.1 with MSTest framework:
Since updating, I have had a similar problem at the end of the scenario, but in this case both ScenarioContext.Current and FeatureContext.Current are null. I can understand the removal of ScenarioContext at that point; although it leaves us with no hook between AfterStep and AfterScenario to do any scenario clean-up/admin work. But, in my case FeatureContext is unavailable too, and I have more than one scenario in this feature; which doesn't make sense unless the FeatureContext is destroyed and recreated mid-feature.

As per #96
I'm setting the TestContext via a partial class

        {
            private TestContext testContext;
            public TestContext TestContext
            {   get  {
                    return this.testContext;
                 }
                 set  {
                    this.testContext = value;
                   //see https://github.com/techtalk/SpecFlow/issues/96
                    this.TestInitialize();
                    FeatureContext.Current["TestContext"] = value;
                }
            }
        }

And...

        [AfterScenario(Order = Constants.DefaultHookHighestOrder)]
        public void CleanUp()
        {   string testName = "";
            if (FeatureContext.Current.ContainsKey("TestContext")) {
                testName = ((TestContext)FeatureContext.Current["TestContext"]).TestName;
            }
            if (ScenarioContext.Current.TestError != null)
            {
                BrowserSupport.TakeScreenshot(context.TestResultPath, context.driver.WrappedDriver, testName);
            }
            /// Data cleanup
            /// etc...
}

@gasparnagy
Copy link
Contributor

@JasonArm I am not aware of any changes in v2.2.1 that would change the availabilit of ScenarioContex or FeatureContext in an AfterScenario hook. They should not be null! Please double check and if you still experience this behavior than create a new issue for that.

Here we were only talking about the availability of the test context in the scenario context. Since the generated code adds it to the scenario context after the "before" hooks it is not available there. But once it is added, it remains there so there should be no problem with the "after" hooks.

@laolubenson
Copy link

laolubenson commented Jan 23, 2018

Are there any another means of obtaining the TestContext? My use case is test runner utility specflow plugin which requires the MsTest TestContext. The main work is done by a class which inherits from the ITestRunner. Ideally I'd like either an AfterFirstStep() method or an event to subscribe to, to do the task required

@gasparnagy
Copy link
Contributor

@akinsolb there is no such thing, I think. You can handle the different step methods and check if it was the first within your plugin.

@githubdhina
Copy link

@SabotageAndi a solution could be to extend the OnScenarioStart to accept a delegate that would be called after the context is created but before the hooks are executed.

Any plans to fix this so the testcontext can be accessed using a scoped before scenario hook?

@SabotageAndi
Copy link
Contributor

Same problem exists also for xUnit: https://groups.google.com/forum/#!topic/specflow/EmiG2gRkIz4

@SabotageAndi
Copy link
Contributor

@githubdhina The delegate suggestion could be a solution. I have currently no plan at looking at this. Reason is, that we will start in the next 2 weeks with .NET Core support. This takes all available time and energy.

@alexvv
Copy link
Contributor

alexvv commented Mar 7, 2018

@SabotageAndi would you be willing to accept/review a PR, or prefer to wait after the .NET core work is complete?
I think @githubdhina proposal to add an OnScenarioStart that accepts a delegate/action as second argument, which is invoked before TestExecutionEngine.FireEvents, could also work for the xUnit ITestOutputhelper injection problem. Then the IUnitTestGeneratorProvider implementations could rewrite 'testRunner.OnScenarioStart(scenarioInfo)' by adding a second argument if necessary (somewhat hacky solution). -Or- an extra interface method could be added to IUnitTestGeneratorProvider, which is invoked in UnitTestGenerator.SetupScenarioInitializeMethod when the 'OnScenarioStart' code is generated and allows an IUnitTestGeneratorProvider to generate extra custom code. Still a little cumbersome, but more explicit.

@SabotageAndi
Copy link
Contributor

SabotageAndi commented Mar 7, 2018

@alexvv I will always accept/reviews PRs. It doesn't depend on our work on .NET Core. As long the .NET Core changes are not in the main branch, it's my problem to merge it back into.
In this case, I think we don't need to do a lot of work at the generators for .NET Core, so lesser work for me. ;-)

@gasparnagy Which way of implementation are you preffering?

@SabotageAndi
Copy link
Contributor

@alexvv If you have a look at this, could you also look at #1072? Looks like the TestContext field initialization is also missing. :-(

@MummanaSubramanya
Copy link

@alexvv can you please provide a fix or any alternative solution for #1072 ?

@MummanaSubramanya
Copy link

@alexvv any update ?

@alexvv
Copy link
Contributor

alexvv commented Mar 19, 2018

@MummanaSubramanya a workaround would be to use 'BeforeStep' and a flag remembering it has already been called instead of 'BeforeScenario', as suggested by @gasparnagy's comment
I will try to submit a PR in the coming days.

@MummanaSubramanya
Copy link

MummanaSubramanya commented Mar 20, 2018

@alexvv I tried the work around but still it throws the same error "Cannot create an instance of Microsoft.VisualStudio.TestTools.UnitTesting.TestContext because it is an abstract class" could you please have a look at the issue #1072 once again

@MummanaSubramanya
Copy link

@alexvv any other work around ?

@alexvv
Copy link
Contributor

alexvv commented Mar 27, 2018

Hi @SabotageAndi, I've submitted PR #1093 to solve this issue. Could you take a look at this please?
I've deviated a little from adding a delegate to OnScenarioStart, instead the instance to be added needs to be supplied as second argument. The reason is that currently only MSTest and XUnit generators need this functionality, and also only for adding a single instance to a scenario container.

@MummanaSubramanya are you sure you removed all [BeforeScenario] attributes in your code? If so, then unfortunately I don't know any other workaround.

@SabotageAndi
Copy link
Contributor

@alexvv I had a look at it and made some comments.

alexvv pushed a commit to alexvv/SpecFlow that referenced this issue Jul 2, 2018
…tions so that they are available in BeforeScenario hooks.

Also added NUnit current TestContext scenario container registration.
See SpecFlowOSS#936
alexvv pushed a commit to alexvv/SpecFlow that referenced this issue Jul 10, 2018
…tions so that they are available in BeforeScenario hooks.

Also added NUnit current TestContext scenario container registration.
See SpecFlowOSS#936
SabotageAndi pushed a commit that referenced this issue Jul 10, 2018
…tions so that they are available in BeforeScenario hooks. (#1093)

Also added NUnit current TestContext scenario container registration.
See #936
@SabotageAndi
Copy link
Contributor

resolved with #1093

@lock
Copy link

lock bot commented Jul 8, 2019

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.

@lock lock bot locked as resolved and limited conversation to collaborators Jul 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants