Безопасен ли поток ScenarioContext.Current? - PullRequest
5 голосов
/ 22 ноября 2011

У меня сложилось впечатление, что это не так.У меня есть три интеграционных теста, которые успешно выполняются по отдельности, но при параллельном выполнении я получаю System.ArgumentException: An item with the same key has already been added.

Я был уверен, что надеюсь, что ScenarioContext.Current всегда ссылается на правильный сценарий, но, похоже, он запутывается.Кто-нибудь успешно добавил безопасность потока в этот класс?Или есть другой подход, который я должен использовать для обмена значениями между файлами шагов?

Ответы [ 3 ]

3 голосов
/ 22 ноября 2011

ScenarioContext.Curent source:

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

1 голос
/ 21 марта 2016

Похоже, это лучше обрабатывается в 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 голосов
/ 03 июля 2015

Я знаю, что это старый пост, но на него ссылаются, так что это мое решение:

Просто замените 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();
    }     

Надеюсь, это кому-нибудь поможет.

...