在 SpecFlow 中,如何在步骤/功能之间共享数据?

发布于 2024-09-02 02:27:17 字数 109 浏览 4 评论 0原文

我有两个功能使用通用的“When”步骤,但在不同的类中具有不同的“Then”步骤。

例如,如何访问两个 Then 步骤中 When 步骤中 MVC 控制器调用的 ActionResult?

I have 2 features that use a common 'When' step but have different 'Then' steps in different classes.

How do I access, for example, the ActionResult from my MVC controller call in the When step in my two Then steps?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

明媚殇 2024-09-09 02:27:17

在 SpecFlow 1.3 中,共有三种方法:

  1. 静态成员
  2. ScenarioContext
  3. ContextInjection

注释:

  1. 静态成员非常实用,在这种情况下并不像我们开发人员首先想到的那么邪恶(没有线程或需要在步骤中进行模拟/替换)定义)

  2. 请参阅@Si的答案,请保留在该线程中

  3. 如果步骤定义类的构造函数需要参数,Specflow 会尝试注入这些参数。这可用于将相同的上下文注入多个步骤定义中。

    请参阅此处的示例:
    https://docs.specflow.org/projects/ specflow/en/latest/Bindings/Context-Injection.html

In SpecFlow 1.3 there are three methods:

  1. static members
  2. ScenarioContext
  3. ContextInjection

Comments:

  1. static members are very pragmatic and in this case not so evil as we as developers might first think (there is no threading or need for mocking/replacing in step-definitions)

  2. See answer from @Si Keep in this thread

  3. If the constructor of a step definition class needs arguments, Specflow tries to inject these arguments. This can be used to inject the same context into several step-definitions.

    See an example here:
    https://docs.specflow.org/projects/specflow/en/latest/Bindings/Context-Injection.html

小耗子 2024-09-09 02:27:17

使用 ScenarioContext 类,它是所有步骤通用的字典。

ScenarioContext.Current.Add("ActionResult", actionResult);
var actionResult = (ActionResult) ScenarioContext.Current["ActionResult"];

Use the ScenarioContext class which is a dictionary that is common to all the steps.

ScenarioContext.Current.Add("ActionResult", actionResult);
var actionResult = (ActionResult) ScenarioContext.Current["ActionResult"];
野侃 2024-09-09 02:27:17

我有一个帮助器类,可以让我编写

Current<Page>.Value = pageObject;

ScenarioContext 的包装器。它与类型名称无关,因此如果您需要访问相同类型的两个变量2019编辑,则需要对其进行一些扩展

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

:我现在会使用@JoeT的答案,看起来您无需定义即可获得相同的好处一个扩展

I have a helper class which lets me write

Current<Page>.Value = pageObject;

which is a wrapper over the ScenarioContext. It works off the type name, so it would need to be extended a bit if you need to access two variables of the same type

 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 edit: I would use @JoeT's answer nowadays, it looks like you get the same benefits without needing to define an extension

紧拥背影 2024-09-09 02:27:17

我不喜欢使用 Scenario.Context,因为需要剔除每个字典条目。我找到了另一种方法来存储和检索该项目,而无需投射它。然而,这里需要权衡,因为您实际上是使用类型作为从 ScenarioContext 字典访问对象的键。这意味着只能存储该类型的一项。

TestPage testPageIn = new TestPage(_driver);
ScenarioContext.Current.Set<TestPage>(testPageIn);
var testPageOut = ScenarioContext.Current.Get<TestPage>();

I did not like using Scenario.Context because of the need for casting out each dictionary entry. I found another way to store and retrieve the item without the needing to cast it. However there is a trade off here because you are effectively using the type as the key access the object from the ScenarioContext dictionary. This means only one item of that type can be stored.

TestPage testPageIn = new TestPage(_driver);
ScenarioContext.Current.Set<TestPage>(testPageIn);
var testPageOut = ScenarioContext.Current.Get<TestPage>();
累赘 2024-09-09 02:27:17

因为这是我在 Google 上找到的第一个结果,所以我想我应该提到 @jbandi 的答案是最完整的。但是,从 3.0 或更高版本开始:

在 SpecFlow 3.0 中,我们将 ScenarioContext.Current 和 FeatureContext.Current 标记为已过时,以明确您将来应避免使用这些属性。放弃这些属性的原因是它们在并行运行场景时不起作用。

SpecFlow 3.0 及更高版本中的 ScenarioContext 和 FeatureContext

因此,在测试期间存储数据的最新方法是使用 上下文注入。我会添加示例代码,但实际上链接中的示例代码非常好,所以请检查一下。

您可以通过将实例注入绑定类来模仿现已过时的 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.
  }
}

Since this is the first result that came up for me on Google, I just thought I'd mention that @jbandi's answer is the most complete. However, as of version 3.0 or later:

With SpecFlow 3.0, we marked ScenarioContext.Current and FeatureContext.Current as obsolete, to make clear that you that you should avoid using these properties in future. The reason for moving away from these properties is that they do not work when running scenarios in parallel.

(ScenarioContext and FeatureContext in SpecFlow 3.0 and Later)

Therefore, the most up to date way to store data during your test is using Context Injection. I would add example code but really the example code in the link is excellent so check it out.

You can imitate the now obsolete ScenarioContext.Current by injecting an instance into your bindings classes

[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.
  }
}
谁对谁错谁最难过 2024-09-09 02:27:17

您可以在步骤中定义一个参数,该参数是您要存储的值的关键。这样您就可以在后续步骤中使用该密钥引用它。

...
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 

您可以将实际值存储在字典或属性包或类似内容中。

You can define a parameter in your steps that is the key to the value you are storing. This way you can reference it in your later steps by using the key.

...
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 

You could store the actual value in a dictionary or property bag or similar.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文