Scenario Context via Context Injection v/s Context Classes via Context Injection
Based on all the research that I have done, there are 2 good ways to share data between step bindings. (1) SpecFlow Scenario Context used with Context Injection and (2) Creating separate Context Classes and using it with Context Injection.
I feel Scenario Context used along with Context injection is better. Which option would you say is better and why?
1) Scenario Context is a SpecFlow feature. .
public class Bindings { private readonly ScenarioContext _scenarioContext;
//Scenario Context public Bindings(ScenarioContext scenarioContext)
//Scenario Context used along with Context Injection { _scenarioContext = scenarioContext; } [Given(@"I have entered (.*) into the calculator")] public void GivenIHaveEnteredIntoTheCalculator(int number) { _scenarioContext["Number1"] = number; }
Pros
- It is simple and easy to use.
- Using it with Context Injection, we don't have issues running parallel tests
- We don't need to maintain separate classes (context classes) to store context which reduces maintenance and also reduces effort to come up with strategy to come up with context classes.
- Scenario context can store not only simple data types but also objects and lot of other information
Cons
- Since scenario context is a dictionary, it stores Key and Value. It may not check for type-safe. We have to explicitly use casts
var userContext = (UserContext)ScenarioContext["userContext"];
-Scenario Context is not available in BeforeRun/AfterRun and BeforeFeature/AfterFeature
2) Context Classes via Context Injection
public class CatalogContext
//This is a sample context class.
///We can have other context class required by Step Definition { public CatalogContext() { ReferenceBooks = new ReferenceBookList(); } public ReferenceBookList ReferenceBooks { get; set; } } [Binding] public class BookSteps { private readonly CatalogContext _catalogContext; //this is a context class
public BookSteps(CatalogContext catalogContext) { _catalogContext = catalogContext; } [Given(@"the following books")] public void GivenTheFollowingBooks(Table table) { foreach (var book in table.CreateSet<Book>()) { SaveBook(book); _catalogContext.ReferenceBooks.Add(book.Id, book); } } }
-Pros
- I guess data to be shared can be organized in a more efficient way??
-Cons
-Data has to be organized into Context classes which takes effort in strategizing.
-If there is one global context class used by all scenarios, the context class can grow a lot and will have lot of fields.
- If we create multiple context classes. Firstly it is difficult to identify criteria for creating context classes (should each business object have its context class), secondly having many context classes will create the constructor of the Step Definition to include many parameter.
-
Use context classes. The handling of the string keys of the dictionary on the ScenarioContext is a pain.
Also, you always have to cast. And not only think about the first time when you introduce it. Think about refactoring.
And use multiple classes. You won't use them all at the same time.
0 -
Thanks for the quick feedback Andreas.
Is there any best practice with respect to creation of Context Classes?
1) In our repo, we are creating Step Definition files based on Domain Object (as recommended in this article: Step Organization - Cucumber Documentation). For example, in a Curriculum Vitae application, we might have:
EmployeeStepDefinitions.java
EducationStepDefinitions.java
ExperienceStepDefinitions.java
AuthenticationStepDefinitions.java
0 -
We recommend structuring the steps to go with which functionality of the application is tested.
Gáspár Nagy explains this very good in lesson 3 of the SpecFlow/BDD Masterclass. You can watch it in our SpecFlow School at https://specflow.org/school/bdd-masterclass/.
This lesson has a whole topic about state sharing.
0
Please sign in to leave a comment.
Comments
3 comments