【问题标题】:Trying to understand Specflow relation to unit test frameworks and BDD试图理解 Specflow 与单元测试框架和 BDD 的关系
【发布时间】:2017-11-08 02:03:20
【问题描述】:

我正在研究像 SpecFlow 这样的 BDD 解决方案并浏览了各种示例,我看到了对我熟悉的其他 TDD 框架(如 MsTest 和 NUnit)的引用。我了解 Specflow 和 BDD 所提供的价值。我在某处读到 Specflow 和 BDD “包装”了您的单元测试。那么,对于 Specflow,“步骤定义”是否与 MsTest 或 Nunit 之类的功能相同,而这些其他框架只是替代步骤定义的选项?

【问题讨论】:

    标签: tdd bdd specflow


    【解决方案1】:

    如果您返回the origins of BDD,您会发现第一个工具 - JBehave - 最初是 JUnit 的替代品。那时还没有注解,所以 JUnit 过去常常寻找以“test”开头的东西:

    测试数据库

    当然,这毫无意义。所以 JBehave 做了同样的事情,但是从“应该”这个词开始:

    应该PersistRecordsUsingHibernate

    所以现在我们可以看到我们的类应该做什么,并用简单的英语谈论它的行为。在这里,“行为”是比“测试”更有用的词。

    一段时间后,Dan North 和 Chris Matts 进行了几次对话后,他们发现 Dan 在课堂上所做的事情与 Chris(当时的分析师)对整个系统所做的事情是一样的,所以场景-running* 组件诞生了。 Dan 将 JBehave 移植到 RBehave,后者成为 RSpec 的场景运行器,后者成为 SpecFlow 和 Cucumber 以及所有其他的。当然,现在的 JUnit 使用注解,所以无论如何我们都可以从“应该”这个词开始,而 NUnit 几乎就是 .NET 的 JUnit。

    关键是您可以使用 BDD 描述任何级别的代码。我将 BDD 用于我的类级示例以及系统级场景。

    对于课程级别的示例,唯一的受众是技术人员。在 NUnit 或 JUnit 中 write comments about how the class behaves 就足够了。一些框架,如 MSpec 或 RSpec 有其他方法来捕获这些描述,但受众仍然是技术人员。它仍然是BDD。通过类级别的示例,我们模拟了依赖关系,因此我们一次只查看行为的一个方面。这有助于推动良好的设计,就像 TDD 一样。

    不过,对于系统级示例,还有其他受众;非技术利益相关者。他们中的大多数人都可以很好地理解可读的代码,所以你也可以在这里制作一个 DSL 和still use NUnit。然而,能够更直接地捕捉自然语言是有好处的,而不必担心让它运行。这就是SpecFlow and the like 发挥作用的地方。

    解析自然语言并将其与步骤匹配的开销不小。在单元/类级别上这样做是不值得的,其中行为被单一职责原则、封装和良好设计的其他方面分开。自然语言也不像代码那样容易重构。

    因此,我们将自然语言场景保存在最外层,我们只需要一些系统行为示例。然后,我们最终得到了一些端到端行为的示例,更多的集成/模块/库级别的场景,以及更多的单元测试(或示例)。这通常被称为“测试金字塔”。

    例如,如果我们想验证一个表单,有几个例子就足以说明我们的应用程序如何帮助用户在犯错时填写表单。我们可能有几个集成测试来检查我们是否在客户端和服务器端都进行了验证(例如,如果这对我们很重要)。然后我们将围绕实际验证类进行大量单元测试,涵盖所有不同的可能性。

    简写回答您的问题:

    • SpecFlow、Cucumber、JBehave 和其他自然语言框架通常仅用于系统级场景,通常针对 UI 自动化。
    • 您不必为此使用框架;可以使用 NUnit(或 JUnit 等)中的 DSL 来实现。
    • 在班级级别使用自然语言框架是多余的。在这里使用 NUnit。
    • BDDers 通常在系统级别运行一层场景,并在其下运行大量类级别示例(单元测试)。这就是您所说的“包装”。
    • 也可能有中间层。

    *“场景”和“示例”这两个词几乎是同义词,意思大致相同。传统上,我们使用“场景”来仅指端到端示例,而“示例”或“单元测试”则用于类级别。

    不过,关于 BDD,最重要的一点是确保你通过与某人讨论这些方面的行为,即使是回想起来或用橡皮擦鸭。 BDD 更多的是关于对话而不是工具。

    【讨论】:

      【解决方案2】:

      简而言之,“步骤定义”与 MsTest 或 Nunit 之类的目的不同。其实我可以写很多,但是文字会太多。让我举一个简单的例子: 这是一个简单的特征文件

      Feature: BingSearchUi
      
      Scenario: Search in Bing
          Given I open page 'http://www.bing.com'
          And I have entered 'visual studio' into the bing search field
          When I press search button on the bing page
          Then the result should contain 'www.visualstudio.com' on the bing page
      

      这是有效的规范流场景,但它本身不能做任何事情。要使其工作,您必须编写代码,并且代码不仅使用 Nunit 或 MsTest。它们可能是步骤实施的一部分,但不是必需的。 例如。这是Given I open page 'http://www.bing.com' 的实现,它实际上使用了 Selenium,而不是任何测试框架:

      [Given(@"I open page '(.*)'")]
       public void GivenIOpenPage(string ulr)
       {            
         driver.Navigate().GoToUrl(ulr);
       }
      

      但是为了让事情变得更复杂,Specflow 会生成带有步骤的 .cs 文件,如果我使用 NUnit,这个文件就是 NUnit 测试类。这是文件的一小部分:

      [NUnit.Framework.TestAttribute()]
              [NUnit.Framework.DescriptionAttribute("Search in Bing")]
              [NUnit.Framework.CategoryAttribute("Selenium")]
              public virtual void SearchInBing()
              {
                  TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Search in Bing", new string[] {
                              "Selenium"});
      #line 15
      this.ScenarioSetup(scenarioInfo);
      #line 16
       testRunner.Given("I open page \'http://www.bing.com\'", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
      #line 17
       testRunner.And("I have entered \'visual studio\' into the bing search field", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
      #line 18
       testRunner.When("I press search button on the bing page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
      #line 19
       testRunner.Then("the result should contain \'www.visualstudio.com\' on the bing page", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
      #line hidden
                  this.ScenarioCleanup();
              }
      

      这个生成的文件实际上是由测试运行程序调用的。

      我认为最简单的方法来了解它是如何工作的 - 在 github 上找到任何使用 specflow 的公共存储库并使用它。

      【讨论】:

        猜你喜欢
        • 2011-05-08
        • 1970-01-01
        • 2011-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-14
        • 1970-01-01
        相关资源
        最近更新 更多