试图理解Specflow与单元测试框架和BDD的关系



我正在研究像SpecFlow这样的BDD解决方案,并通过各种示例,我看到了对其他TDD框架的引用,如我熟悉的MsTest和NUnit。我理解Specflow和BDD所提供的价值。我在某个地方读到Specflow和BDD"包装"了您的单元测试。那么,对于Specflow,"步骤定义"是否与MsTest或Nunit一样具有相同的目的,而这些其他框架只是可以使用的选项,而不是步骤定义?

如果你回到BDD的起源,你会发现有史以来第一个工具JBehave最初是JUnit的替代品。注释在当时还不是一件事,所以JUnit过去常常寻找以"测试"一词开头的东西:

testDatabase

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

应该使用休眠来保持记录

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

过了一段时间,Dan North和Chris Matts进行了几次对话,他们发现Dan对类所做的事情与Chris(当时是一名分析师)对整个系统所做的相同,因此运行场景组件诞生了。Dan将JBehave移植到RBehave,后者成为RSpec的场景运行程序,后者成为SpecFlow和Cucumber以及其他所有程序。当然,JUnit现在使用注释,所以我们无论如何都可以用"应该"这个词开始,而NUnit相当于.NET的JUnit

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

对于班级级别的例子,唯一的受众是技术人员。写一些关于类在NUnit或JUnit中的行为的注释就足够了。像MSpec或RSpec这样的一些框架有其他方法来捕捉这些描述,但受众仍然是技术性的。它仍然是BDD。通过类级别的例子,我们模拟了依赖关系,这样我们一次只关注行为的一个方面。这有助于推动良好的设计,就像TDD一样。

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

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

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

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

用简写回答您的问题:

  • SpecFlow、Cucumber、JBehave和其他自然语言框架通常仅用于系统级场景,通常针对UI进行自动化
  • 你不必使用这些框架;可以在NUnit(或JUnit等)中使用DSL来实现
  • 在课堂上使用自然语言框架是过分的。在此处使用NUnit
  • BDDer通常有一层在系统级运行的场景,以及大量的类级示例(单元测试)。这就是你所说的"包装">
  • 也可能存在中间层

*单词"scenario"one_answers"example"几乎是同义词,意思几乎相同。传统上,我们使用"场景"仅指端到端的示例,在类级别使用"示例"或"单元测试"。

不过,关于BDD,最重要的一件事是确保你与某人谈论行为的这些方面,即使是回顾过去或与橡皮鸭交谈。BDD更多的是关于对话,而不是关于工具。

简而言之,"步骤定义"的作用与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

这是一个有效的specflow场景,但它本身什么都做不了。为了让它发挥作用,你必须编写代码,而代码不仅使用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的公共存储库并使用它

最新更新