Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

Scoping Context Injection to Scenario Execution Lifetimes #12

Closed
rtlayzell opened this issue Oct 30, 2019 · 8 comments · Fixed by #74
Closed

Scoping Context Injection to Scenario Execution Lifetimes #12

rtlayzell opened this issue Oct 30, 2019 · 8 comments · Fixed by #74
Assignees
Labels
question Further information is requested

Comments

@rtlayzell
Copy link

rtlayzell commented Oct 30, 2019

The default Context Injection in SpecFlow is scoped to the life-time of scenario execution, how do we go about achieving this with SpecFlow.DependencyInjection?

As steps are global across the entire project, I have separated the steps into logical units/binding classes where a single scenario may invoke steps from multiple bindings. This means I need to share the same context instance between each. Right now I'm having trouble because each binding class is receiving its own context instance. Adding the context instances as singletons won't help either.

@rtlayzell rtlayzell changed the title Scoping Context Injection to Scenarios Execution Lifetimes Scoping Context Injection to Scenario Execution Lifetimes Oct 30, 2019
mbhoek added a commit that referenced this issue Oct 30, 2019
@mbhoek mbhoek added the question Further information is requested label Oct 30, 2019
@mbhoek
Copy link
Member

mbhoek commented Oct 30, 2019

Thanks for your question. To ensure that I've understood you correctly, I've added a new test covering what I think you're asking in #13 . The code for the steps is here: https://github.com/solidtoken/SpecFlow.DependencyInjection/blob/ee17443863d1004840e9f75b6aab1e426ccfa5c9/SpecFlow.DependencyInjection.Tests/ContextInjectionScopeSteps.cs

TL;DR: if you inject the Context using AddScoped instead of AddTransient, the context will be kept across the entire Feature. If you use AddTransient, each Binding will get a new Context. In the case of this example I add the TextContext using:

    services.AddScoped<TestContext>();

Let me know if this answers your question.

@rtlayzell
Copy link
Author

Hey @mbhoek, that seems to do the trick! I was under the impression that AddScoped was specific to the lifetime of an HTTP request. It would be interesting to know how that works in the context of SpecFlow scenarios.

@mbhoek
Copy link
Member

mbhoek commented Oct 30, 2019

Understandable, because many examples on the web are about dependency injection in ASP.NET so in that case AddScoped is indeed specific to the lifetime of an Http Request. However, AddScoped actually relates to any client lifetime scope, so e.g. in an Azure Function the scope is the lifetime of the function.

In the case of SpecFlow.DependencyInjection the client lifetime is the lifetime of one Scenario.

I'll keep the example in the test set. Thanks for your feedback!

@mbhoek mbhoek closed this as completed Oct 30, 2019
mbhoek added a commit that referenced this issue Oct 30, 2019
@RogerSillito-CAL
Copy link

RogerSillito-CAL commented Nov 10, 2021

@mbhoek - your comments above confused me a little; where you have stated

TL;DR: if you inject the Context using AddScoped instead of AddTransient, the context will be kept across the entire Feature.

Should that say

TL;DR: if you inject the Context using AddScoped instead of AddTransient, the context will be kept across the entire Scenario.

? That makes more sense to me, given the test you've referenced?

Also in that test where there is a caution against using parallel tests - I'm thinking that doesn't actually matter? Given SpecFlow only supports feature/fixture-level parallelism, your test case works just the same in a parallel context too.

I tried out a separate parallel test using multiple copies of your feature file - that works fine too, with a new TestContext is supplied to each scenario, within each parallel-ran feature:

parallel (all)

(so here we get 20 instances of TestContext created in this test run, which has a parallelism of 10)

@mbhoek
Copy link
Member

mbhoek commented Nov 16, 2021

@RogerSillito-CAL Yeah, what you're saying does seem to make more sense. I'll have to dig into it a little deeper to make sure (the issue you're commenting on is over 2 years old), so let me get back to this.

@mbhoek mbhoek reopened this Nov 16, 2021
@StevenDenman
Copy link

StevenDenman commented Jan 27, 2022

I have started to look into using this and I cannot make an instance of a class be reused by multiple scenarios.

Using AddScoped - this ensures that the same instance is used throughout the scenario
Using AddSingleton - as [ScenarioDependencies] method is called for each scenario this behaves as above as a new ServiceCollection is created per scenario
Using AddTransient - this makes it so that a new instance is called for different scopes (e.g. I had steps in one file and steps in a different file, they got different instances)

The only workaround I can think of is creating an instance of the object and saving a reference to it and adding that same reference into the ServiceCollection for each [ScenarioDependencies] in each scenario using .AddSingleton(testClassInstance)

@Loydik
Copy link

Loydik commented Mar 7, 2022

@StevenDenman having the same issue, need to reuse the same instance between tests

@mbhoek mbhoek linked a pull request May 7, 2022 that will close this issue
@mbhoek
Copy link
Member

mbhoek commented May 7, 2022

Thanks to @shlomiassaf and their excellent work in #74 I believe that many (if not all) scoping issues should be solved.
Please try out the latest preview version and let me know.

@mbhoek mbhoek closed this as completed May 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
question Further information is requested
Development

Successfully merging a pull request may close this issue.

5 participants