Is ScenarioContext.Current script safe?

I get the impression that this is not so. I have three integration tests that are performed individually, but when I run in parallel, I get a System.ArgumentException: An item with the same key has already been added.

I was sure that ScenarioContext.Current always refers to the correct script, but it seems to get confused. Has anyone successfully added thread safety to this class? Or is there another approach I should use to exchange values ​​between step files?

+4
source share
3 answers

ScenarioContext.Curent source:

 public static ScenarioContext Current { get { if (current == null) { Debug.WriteLine("Accessing NULL ScenarioContext"); } return current; } internal set { current = value; } } 

As you can see, this is not thread safe https://github.com/techtalk/SpecFlow/blob/master/Runtime/ScenarioContext.cs

+3
source

In SpecFlow V2, it looks more beautiful: http://www.specflow.org/documentation/Parallel-Execution/

Extract (easier options):

 [Binding] public class StepsWithScenarioContext : Steps { [Given(@"I put something into the context")] public void GivenIPutSomethingIntoTheContext() { this.ScenarioContext.Set("test-value", "test-key"); } } 
+1
source

I know this is an old post, but it is indicated on it, so this is my solution:

Just replace ScenarioContext with your own implementation as follows:

  public class ScenarioContextSafe { private static ScenarioContextSafe _current; private static readonly object Locker = new object(); public static ScenarioContextSafe Current { get { lock (Locker) { return _current ?? (_current = new ScenarioContextSafe()); } } } public static void Reset() { lock (Locker) { _current = null; } } private readonly ConcurrentDictionary<string, object> _concurrentDictionary = new ConcurrentDictionary<string, object>(); public void Add(string key, object value) { _concurrentDictionary.TryAdd(key, value); } public void Set(object value, string key) { if (!_concurrentDictionary.ContainsKey(key)) _concurrentDictionary.TryAdd(key, value); else _concurrentDictionary[key] = value; } public void Remove(string key) { object result; _concurrentDictionary.TryRemove(key, out result); } public T Get<T>(string key) { object result; _concurrentDictionary.TryGetValue(key, out result); return (T)result; } public bool ContainsKey(string key) { return _concurrentDictionary.ContainsKey(key); } public void Pending() { ScenarioContext.Current.Pending(); } public ScenarioInfo ScenarioInfo{ get { return ScenarioContext.Current.ScenarioInfo; } } } 

Then create a hook to reset the context before each script.

  [BeforeScenario()] public static void BeforeAllScenario() { ScenarioContextSafe.Reset(); } 

I hope this helps someone.

0
source

Source: https://habr.com/ru/post/1382378/


All Articles