ScenarioContext.Current 是线程安全的吗?

6

我有这样的印象,似乎不是这样的。当我单独运行三个集成测试时,它们都能够成功,但是并行运行时,我遇到了System.ArgumentException: An item with the same key has already been added.

我原本以为ScenarioContext.Current总是指向正确的场景,但现在看来好像出现了混淆。是否有人已经成功地将线程安全添加到这个类中?或者我应该使用另一种方法来在步骤文件之间共享值呢?

3个回答

3

1
谢谢。你知道在并行运行测试时分享值的更好方法吗?我认为使用FeatureContext和上下文注入可能会解决一些并发问题,但是在绑定之间共享仍然成为一个问题,特别是当步骤绑定更通用且与任何特定功能无关时。 - Samo
FeatureContext和ScenarioContext都可以使用上下文注入进行注入。 - bytedev
@Andrew 我认为 ScenarioContext.cs 已经移动到:https://github.com/techtalk/SpecFlow/blob/master/TechTalk.SpecFlow/ScenarioContext.cs - bytedev

1
This appears to be handled more nicely in 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");
    }
}

0

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

只需像这样替换ScenarioContext为自定义实现:

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

我希望这能帮助到某个人。


无法解决问题,因为仍然只有一个“Current”,但是每个线程都需要一个。请使用类似于https://msdn.microsoft.com/en-us/library/dd642243(v=vs.110).aspx的东西。 - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接