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

C# 在SpecFlow中,如何在步骤/功能之间共享数据?,c#,specflow,C#,Specflow,我有两个功能,它们使用一个常见的“When”步骤,但在不同的类中有不同的“Then”步骤 例如,如何访问我的两个Then步骤中的When步骤中MVC控制器调用的ActionResult?使用ScenarioContext类,该类是所有步骤通用的字典 ScenarioContext.Current.Add("ActionResult", actionResult); var actionResult = (ActionResult) ScenarioContext.Current["ActionR

我有两个功能,它们使用一个常见的“When”步骤,但在不同的类中有不同的“Then”步骤


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

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

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

在SpecFlow 1.3中,有三种方法:

  • 静态成员
  • 情景语境
  • 上下文注入
  • 评论:

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

  • 请参阅此线程中@Si Keep的答案

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

    请参见此处的示例:


  • 我有一个助手类,可以让我写作

    Current<Page>.Value = pageObject;
    
    Current.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; }
         }
     }
    
    当前公共静态类,其中T:class
    {
    内部静态T值
    {
    获取{
    返回ScenarioContext.Current.ContainsKey(typeof(T).FullName)
    ?ScenarioContext.Current[typeof(T).FullName]为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>();
    
    TestPage testPageIn=newtestpage(\u驱动程序);
    ScenarioContext.Current.Set(testPageIn);
    var testPageOut=ScenarioContext.Current.Get();
    
    您可以在步骤中定义一个参数,该参数是存储值的关键。这样,您可以在以后的步骤中使用键引用它

    ...
    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 
    
    。。。
    然后我记得车票号码“
    ....
    当我在搜索框中键入我的票号“”时
    然后我应该在结果中看到我的票号“”
    

    您可以将实际值存储在字典、属性包或类似的工具中。

    由于这是我在谷歌上得到的第一个结果,我想我应该提到@jbandi的答案是最完整的。但是,从3.0或更高版本开始:

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

    ()

    因此,在测试期间存储数据的最新方法是使用。我想添加示例代码,但实际上链接中的示例代码非常好,请查看

    您可以通过向绑定类中注入实例来模拟现在已经过时的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.
      }
    }
    
    [绑定]
    公共类MyStepDefs
    {
    私有只读场景上下文\u场景上下文;
    公共MyStepDefs(场景上下文场景上下文)
    { 
    _scenarioContext=scenarioContext;
    }
    公共方法()
    {
    _情景语境。添加(“关键”、“价值”);
    var someObjectInstance=new SomeObject();
    _scenarioContext.Set(someObjectInstance);
    _scenarioContext.Get();
    //等等。
    }
    }
    
    我认为实例变量也可以使用,就像它们的一个例子一样:@Carl:instance变量可以用于在同一类中实现的step定义之间共享数据。但问题是关于不同类中的STEP实现。ScenarioContext相对于静态成员的优势是,状态可以与其他测试类共享,因此可以自由编辑in.feature文件。这一页很好地解释了这三种方法:只看了一个使用静态的示例,它变得非常混乱,所以这仍然是一个问题。为什么说ye是可怕的上校?Simon已经为这个问题做了正确的实现。op现在可以根据需要进行重构,而不是Simon试图猜测他想要的是什么。mcintyre321在下面提供了一个很好的助手方法。请注意,ScenarioContext.Current现在已经过时了-请查看我的答案。您还可以使集合更简洁,例如ScenarioContext.Current.Set(testPageIn);我有点喜欢让代码显示类型是存储和检索对象的“键”。如果我们存储对象而不指定类型,那么检索所需的键就不那么明显了。但是,通过查看周围的代码,确定该类型应该非常容易。它可能需要少量额外的脑力劳动来确定该对象的类型以写入检索该对象的行,而不是查看存储该对象的行中已拼写出的类型。