是的,只需要5行,我们就完成了填写表单的步骤定义。我们首先循环表中的行,然后试图查找相应的带有命名属性的field文本,用来匹配当前行中field列值。如果没有匹配到相应的文本field,测试将会失败(但是会有相应信息被记录下来)。但是如果我们找到一个匹配的文本field,WatiN将会被指示输入在当前行所找到的列值。 接下来剩余的步骤定义也基本类似。以下就是我们下个步骤的代码:“And I click the ‘Login’button”。 [When("I click the 'Login' button")]
public void AndIClickTheLoginButton()
{
var loginButton = WebBrowser.Current.Button(Find.ByValue("Login"));if(!loginButton.Exists)
Assert.Fail("Expected to find a button with the value of 'Login'."); loginButton.Click();
}
|
而最后一步,我们则需要弄清如何去验证我们是否在主页上。我们可以检测其文件标题来看它是否满足我们的需要;或者检测URL来查看其是否与期望的主页URL匹配。这里我们将通过URL来检测。但需要记住的是步骤定义的执行会完全依赖于具体应用:如果我们大量使用Ajax进行页面切换,URL可能不会被更新,从而可能无法验证我们是否在正确页面上。 [Then("I should be at the 'Home' page")]
public void ThenIShouldBeAtTheHomePage()
{
var expectedURL = "http://localhost:9876/";
var actualURL = WebBrowser.Current.Url;
Assert.AreEqual(expectedURL, actualURL);
}
|
现在重新执行验收测试,而这次它将执行所有步骤。如果成功了,那么恭喜你,你成功地通过Spec Flow编写了第一个验收测试。 重构测试代码现在我们的步骤定义已经成功运行了,可是我们还是需要停下来回顾一下。我们已经有了针对登录按钮的步骤定义,有很大可能我们的应用中将有大量的按钮。我们是否为验收测试集中的每个按钮提供一个步骤定义呢?这些步骤定义中唯一一个需要修改的地方就是WatiN在某页面上寻找期望按钮所对应的具体文本,以下就是个例子: [When("I click the 'Login' button")]
public void AndIClickTheLoginButton()
{
var loginButton = WebBrowser.Current.Button(Find.ByValue("Login"));if(!loginButton.Exists)
Assert.Fail("Expected to find a button with the value of 'Login'.");
loginButton.Click();
}
[When("I click the 'Register' button")]
public void AndIClickTheRegisterButton()
{
var registerButton = WebBrowser.Current.Button(Find.ByValue("Register"));
if(!registerButton.Exists)
Assert.Fail("Expected to find a button with the value of 'Register'.");
registerButton.Click();
}
|
幸运的是,Spec Flow为该问题提供了解决方案。你可以使用正则表达式,该表达式必须是传递给绑定属性的字符串,这样我们就将不同步骤绑定到同一个步骤定义。任何由该正则表达式捕获的文本都可以当作一个参数传递给步骤定义。具体例子如下: [When("I click the '(.*)' button")]
public void AndIClickAButton(string buttonText)
{
var button = WebBrowser.Current.Button(Find.ByValue(buttonText));if(!button.Exists)
Assert.Fail("Expected to find a button with the value of '{0}'.", buttonText);
button.Click();
}
|
该步骤定义可以是以下任意一种: 点击‘登陆’按钮 点击‘注册’按钮 点击‘任意文本’按钮 你可以使用该技巧来让所有步骤定义可重用。让所有的步骤定义都具有可重用性是个非常好的想法,我们应该避免编写只有某一特定情景才可以用的步骤定义。可重用性允许你写出的Scenario能立即使用,因为你已经拥有一个可以重复使用的步骤定义。但是也没必要在需要前就把步骤定义编写出来,在需要时编写就好了。大多数情况下,你的测试所需要做的基本上是同样的事情:跳转到一个页面,填写表单,点击之类的。只有在极少数情况下,你才需要为一个情景编写特殊步骤定义,比如验证jQuery UI日历是否在点击一个需要日期值的文本框时弹出,这样不寻常的例子时候才需要。 对于具体如何重构你的步骤定义,我将其作为练习留给你,确保每个都具有可重用性。之后,你就可以编写新的特性文件,而因为所需的步骤定义都已经准备好了,它们都可以立刻工作。当然,你将需要更多的步骤定义来自动化不同行为(比如:点击一个链接),你也需要进一步改善当前步骤定义,以便在不同情景中也能使用。你将注意到我们的表单填充步骤定义中处理的表单只带有文本框。如果你想勾选复选框,通过value或ID寻找按钮,或其它与表单相关操作,那你就需要在表单填充步骤定义中添加相应的逻辑。总结总之,以上就是使用Spec Flow编写验收测试之旅。尽管如此,Spec Flow依然有更多特性需要你自己去发现。比如:Spec Flow还有个跟踪机制,因此你能跟踪某个指定特性在特定特性,情景或步骤前后是如何执行某些代码。对于以下情况,它就会起到非常大的作用,比如:如果你需要在完成含有登陆功能的场景后的登出;测试前准备数据库,或只是简单地在每个测试结束后关闭浏览器窗口。 随着测试不断被创建,你会发现完成验收测试集所需的时间也会随之增加。但是你的测试执行得越快,你就能越快得到回馈,并找到问题所在。你需要尽可能快地执行你的测试。方法之一就是将你的测试并行化,而非按顺序执行,所有测试将一起执行,而且将更快结束。但是Spec Flow并没有提供并行处理功能,因此需要从别处想办法。如果你使用NUnit,你可以查看PNUnit看其是否满足你的并行需求。 Gherkin,我们曾经是使用DSL来编写我们的详细需求,它被设计作为衔接技术人员与非技术利益相关者之间的桥梁,以便他们在某一特定特性应该如何运行上能够达成一致。有的团队甚至有非技术利益相关者参与到使用Given-When-Then语句来编写实际详细需求。可以想象到,培训大家如何做到这点并不太难,但是其结果却大大不同。 也有一部分人更进一步地使用Spec Flow。他们在开始所有新特性开发时,首先就是编写详细需求,接着单元测试,最后才是真正的编码。然后他们通过常规的TDD red-green-refactor循环通过单元测试,最后通过验收测试。如果你已经在实践TDD,打算为项目编写验收测试,那你应该尝试下验收测试驱动开发。 无论你是通过什么途径,你都需确保它对你、还有你的工程都要行之有效。如果你还处于建模状态,并不断修改你的应用,持续更新验收测试可能会造成一定时间拖延。什么时候应该着手编写验收测试是你的决定,只有你能保证它将发生。
|