Question

I have 2 features that use a common 'When' step but have different 'Then' steps in different classes.

How do I access, for example, the ActionResult from my MVC controller call in the When step in my two Then steps?

Was it helpful?

Solution

In SpecFlow 1.3 there are three methods:

  1. static members
  2. ScenarioContext
  3. ContextInjection

Comments:

  1. static members are very pragmatic and in this case not so evil as we as developers might first think (there is no threading or need for mocking/replacing in step-definitions)

  2. See answer from @Si Keep in this thread

  3. If the constructor of a step definition class needs arguments, Specflow tries to inject these arguments. This can be used to inject the same context into several step-definitions.
    See an example here: https://github.com/techtalk/SpecFlow/wiki/Context-Injection

OTHER TIPS

Use the ScenarioContext class which is a dictionary that is common to all the steps.

ScenarioContext.Current.Add("ActionResult", actionResult);
var actionResult = (ActionResult) ScenarioContext.Current["ActionResult"];

I have a helper class which lets me write

Current<Page>.Value = pageObject;

which is a wrapper over the ScenarioContext. It works off the type name, so it would need to be extended a bit if you need to access two variables of the same type

 public static class Current<T> where T : class
 {
     internal static T Value 
     {
         get { 
               return ScenarioContext.Current.ContainsKey(typeof(T).FullName)
               ? ScenarioContext.Current[typeof(T).FullName] as T : null;
             }
         set { ScenarioContext.Current[typeof(T).FullName] = value; }
     }
 }

2019 edit: I would use @JoeT's answer nowadays, it looks like you get the same benefits without needing to define an extension

I did not like using Scenario.Context because of the need for casting out each dictionary entry. I found another way to store and retrieve the item without the needing to cast it. However there is a trade off here because you are effectively using the type as the key access the object from the ScenarioContext dictionary. This means only one item of that type can be stored.

TestPage testPageIn = new TestPage(_driver);
ScenarioContext.Current.Set<TestPage>(testPageIn);
var testPageOut = ScenarioContext.Current.Get<TestPage>();

You can define a parameter in your steps that is the key to the value you are storing. This way you can reference it in your later steps by using the key.

...
Then I remember the ticket number '<MyKey>'
....
When I type my ticket number '<MyKey>' into the search box
Then I should see my ticket number '<MyKey>' in the results 

You could store the actual value in a dictionary or property bag or similar.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top