ScenarioContext.当前线程安全

本文关键字:安全 线程 前线 ScenarioContext | 更新日期: 2023-09-27 18:15:25

我得到的印象是它不是。我有三个单独运行时成功的集成测试,但当并行运行时,我得到System.ArgumentException: An item with the same key has already been added.

我肯定希望ScenarioContext.Current总是指正确的场景,但它似乎变得混乱。有人成功地为这个类添加了线程安全吗?或者我应该使用另一种方法来在步骤文件之间共享值?

ScenarioContext.当前线程安全

场景上下文。颇来源:

public static ScenarioContext Current
    {
        get
        {
            if (current == null)
            {
                Debug.WriteLine("Accessing NULL ScenarioContext");
            }
            return current;
        }
        internal set { current = value; }
    }
如你所见,它不是线程安全的https://github.com/techtalk/SpecFlow/blob/master/Runtime/ScenarioContext.cs

这似乎在SpecFlow V2中处理得更好:http://www.specflow.org/documentation/Parallel-Execution/

提取(更简单的选项):

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

我知道这是一个旧的帖子,但它是很好的参考,所以这是我的解决方案:

将场景上下文替换为如下的自定义实现:

 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; }
    }
}

然后,在每个场景之前创建一个钩子来重置上下文

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