У меня есть 2 функции, которые используют общий шаг «Когда», но разные шаги «Тогда» в разных классах.
Как мне получить доступ, например, к ActionResult из моего вызова контроллера MVC на шаге When в моих двух шагах Then?
У меня есть 2 функции, которые используют общий шаг «Когда», но разные шаги «Тогда» в разных классах.
Как мне получить доступ, например, к ActionResult из моего вызова контроллера MVC на шаге When в моих двух шагах Then?
В SpecFlow 1.3 есть три метода:
Комментарии:
статические члены очень прагматичны и в этом случае не такие злые, как мы, как разработчики, могли бы сначала подумать (нет потоковой передачи или необходимости в насмешке / замене в определениях шагов)
См. Ответ от @Si Keep в этой теме
Если конструктору класса определения шага нужны аргументы, Specflow пытается внедрить эти аргументы. Это можно использовать для вставки одного и того же контекста в несколько определений шагов.
См. Пример здесь: https://docs.specflow.org/projects/specflow/en/latest/Bindings/Context-Injection.html
Используйте класс ScenarioContext, который представляет собой словарь, общий для всех шагов.
ScenarioContext.Current.Add("ActionResult", actionResult);
var actionResult = (ActionResult) ScenarioContext.Current["ActionResult"];
У меня есть вспомогательный класс, который позволяет мне писать
Current<Page>.Value = pageObject;
который является оболочкой для ScenarioContext. Он работает с именем типа, поэтому его нужно немного расширить, если вам нужно получить доступ к двум переменным одного и того же типа.
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: в настоящее время я бы использовал ответ @ JoeT, похоже, вы получаете те же преимущества, не определяя расширение
Мне не нравилось использовать Scenario.Context из-за необходимости отбрасывать каждую словарную статью. Я нашел другой способ сохранить и получить элемент без необходимости его использовать. Однако здесь есть компромисс, потому что вы эффективно используете тип в качестве ключа для доступа к объекту из словаря ScenarioContext. Это означает, что можно сохранить только один элемент этого типа.
TestPage testPageIn = new TestPage(_driver);
ScenarioContext.Current.Set<TestPage>(testPageIn);
var testPageOut = ScenarioContext.Current.Get<TestPage>();
Вы можете определить в своих шагах параметр, который является ключом к сохраняемому значению. Таким образом, вы можете ссылаться на него на более поздних этапах с помощью ключа.
...
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
Вы можете сохранить фактическое значение в словаре, в сумке с недвижимостью или в чем-то подобном.
Поскольку это первый результат, который пришел мне в голову в Google, я просто подумал, что упомянул, что ответ @ jbandi является наиболее полным. Однако начиная с версии 3.0 и новее:
В SpecFlow 3.0 мы пометили ScenarioContext.Current и FeatureContext.Current как устаревшие, чтобы прояснить, что вам следует избегать использования этих свойств в будущем. Причина отказа от этих свойств заключается в том, что они не работают при параллельном запуске сценариев.
(ScenarioContext и FeatureContext в SpecFlow 3.0 и более поздних версиях)
Поэтому наиболее актуальным способом хранения данных во время тестирования является использование Внедрение контекста. Я бы добавил пример кода, но на самом деле пример кода в ссылке отличный, так что проверьте его.
Вы можете имитировать устаревший ScenarioContext.Current, внедрив экземпляр в свои классы привязки
[Binding]
public class MyStepDefs
{
private readonly ScenarioContext _scenarioContext;
public MyStepDefs(ScenarioContext scenarioContext)
{
_scenarioContext= scenarioContext ;
}
public SomeMethod()
{
_scenarioContext.Add("key", "value");
var someObjectInstance = new SomeObject();
_scenarioContext.Set<SomeObject>(someObjectInstance);
_scenarioContext.Get<SomeObject>();
// etc.
}
}