Behavior Driven Development 行为驱动开发入门
最近参加了 Toughtworks 的一次线下 Workshop,有幸头一次体验并实战了 BDD。感觉非常不错。
主题是:从 0 到 1 搭建自动化测试框架。围绕 BDD 进行,就如题目所说,翻译过来就是行为驱动开发,这是一种敏捷软件开发的技术,它鼓励软件项目中的 开发者、QA 和非技术人员或商业参与者之间的协作。BDD 最初是由 Dan North 在 2003 年命名,它包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。在过去数年里,它得到了很大的发展。
在我的理解中,这个定义过程,弱化了当前需求职能在对接业务和研发过程中的翻译属性,而强化了解释属性。解释源头可以交由客户来定义。
前期基础环境准备如下:
- Windows 系统环境搭建请参考: https://note.youdao.com/share/id=1465ad112ca09d244710a68881d04ad2&type=note#/
- Mac 系统环境搭建请参考: http://note.youdao.com/noteshare?id=1fd3e24d52158463b05d705403a9c154
为了方便 gradle 项目的构建,此处使用的 IDE 是 IntellJ IDEA ,我的版本是 15。
拿一个最小的测试用例来讲,可以将期解剖为 3 部分:
- 定义
- 执行
- 控制执行过程
项目结构如下,如上 3 部分对应的文件在截屏中有指示:
让我们来看看第一部分:定义
baidu.feture 文件:
Feature: Workshop baidu first case
@first
Scenario: Search cucumber
Given : I open a baidu homepage "http://www.baidu.com"
When : I input "cucumber" in searchbox
Then : I will see page title contains "cucumber"
在此处我们定义了一条用例,描述是说:当用户打开百度搜索页的时候,输入一个关键字"cucumber"并点按搜索,然后检查搜索结果页的标题是否包含了刚才输入的关键字。
然后这个定义是如何启动的呢?看第二部分:执行
build.gradle 文件,重点看 cucumberBaidu() 方法:
apply plugin: 'java'
sourceCompatibility = 1.10
version = '1.0'
configurations {
cucumberRuntime {
extendsFrom testRuntime
}
}
repositories {
mavenCentral()
}
dependencies {
compile 'org.springframework:spring-context:4.2.1.RELEASE'
compile 'junit:junit:4.12'
compile 'org.seleniumhq.selenium:selenium-java:3.4.0'
compile 'info.cukes:cucumber-core:1.1.2'
compile 'info.cukes:cucumber-java:1.1.2'
compile 'info.cukes:cucumber-junit:1.1.2'
testCompile 'io.cucumber:cucumber-java:2.4.0'
testCompile 'io.cucumber:cucumber-junit:2.4.0'
testCompile 'junit:junit:4.12'
}
task cucumberBaidu() {
dependsOn assemble, compileTestJava
doLast {
javaexec {
main = "cucumber.api.cli.Main"
classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
args = ['-f', 'pretty', '--glue', 'baidu_step', 'src/test/resources/cucumber/baidu.feature']
}
}
}
然后看第三部分,我们通过什么样的办法来自动化输入关键字并触发检索呢?
baidu_step.java 文件,定义中引号的部分转换为 java 方法中的入参。如下:
package baidu_step;
import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
/**
* Created by bianxh on 2018/3/31.
*/
public class baidu_step {
WebDriver driver = null;
public void initializeDriver()
{
driver = new ChromeDriver();
}
@Given("^: I open a baidu homepage \"([^\"]*)\"$")
public void _I_open_a_baidu_homepage(String open_url) throws Throwable {
initializeDriver();
driver.get(open_url);
}
@When("^: I input \"([^\"]*)\" in searchbox$")
public void _I_input_in_searchbox(String Keyword) throws Throwable {
WebElement element = driver.findElement(By.cssSelector("#kw"));
element.sendKeys(Keyword);
WebElement element1 = driver.findElement(By.cssSelector("input#su"));
// WebElement element1 = driver.findElement(By.cssSelector("input#su"));
// WebElement element1 = driver.findElement(By.className("bg s_btn"));
element1.click();
}
@Then("^: I will see page title contains \"([^\"]*)\"$")
public void _I_will_see_page_title_contains(String Result) throws Throwable {
// throw new PendingException();
Thread.sleep(2000);
System.out.println("title:" + driver.getTitle());
driver.getTitle().contains(Result);
driver.close();
}
}
最后,我们在控制台执行:
bianxh:group_five_art bianxh$ gradle cucumberBaidu
> Task :cucumberBaidu
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by cucumber.deps.com.thoughtworks.xstream.converters.collections.TreeMapConverter (file:/Users/bianxh/.gradle/caches/modules-2/files-2.1/info.cukes/cucumber-core/1.1.2/423d83b02d6a2409c21264023ad7b87d625be59e/cucumber-core-1.1.2.jar) to field java.util.TreeMap.comparator
WARNING: Please consider reporting this to the maintainers of cucumber.deps.com.thoughtworks.xstream.converters.collections.TreeMapConverter
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Starting ChromeDriver 2.36.540469 (1881fd7f8641508feb5166b7cae561d87723cfa8) on port 1468
Only local connections are allowed.
4 月 02, 2018 8:04:17 下午 org.openqa.selenium.remote.ProtocolHandshake createSession
信息: Detected dialect: OSS
title:cucumber_百度搜索
Feature: Workshop baidu first case
@first
Scenario: Search cucumber # src/test/resources/cucumber/baidu.feature:4
Given : I open a baidu homepage "http://www.baidu.com" # baidu_step._I_open_a_baidu_homepage(String)
When : I input "cucumber" in searchbox # baidu_step._I_input_in_searchbox(String)
Then : I will see page title contains "cucumber" # baidu_step._I_will_see_page_title_contains(String)
BUILD SUCCESSFUL in 7s
3 actionable tasks: 2 executed, 1 up-to-date
结果如下:
可以看到单个测试成功了。
注:通过 drive.close();可以关闭 chrome 浏览器。
那如果我们要定义一组 feature 来测试呢?
定义如下:
@first_group
Scenario Outline: multi-data test
Given : I open a baidu homepage "<open_url>"
When : Input "<Keyword>"
Then : See "<Result>"
Examples:
|open_url | Keyword | Result |
|http://www.hao123.com | abc | abc |
|http://www.hao123.com | abc1 | abc1 |
注意参数用<>进行了定义,执行代码中对多出来的部分进行控制,新增的代码如下:
// 2 feature
@When("^: Input \"([^\"]*)\"$")
public void _Input(String Keyword) throws Throwable {
WebElement element = driver.findElement(By.cssSelector("#search-input"));
element.sendKeys(Keyword);
WebElement element1 = driver.findElement(By.cssSelector("#search-form > div.button-wrapper.g-ib > input"));
element1.click();
}
@Then("^: See \"([^\"]*)\"$")
public void _See(String Result) throws Throwable {
Thread.sleep(2000);
System.out.println("title:" + driver.getTitle());
driver.getTitle().contains(Result);
driver.close();
}
注:关于截取网页元素的时候,可以通过 chrome 工具抓取 selector 来确保唯一性,这个一般可以应对后续的网页变化(网页更新时,测试用例代码改动较少)。
抓取后获取和使用办法如下:
WebElement element1 = driver.findElement(By.cssSelector("input#su"));
// 模拟点击事件
element1.click();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 小米路由硬盘版搭建 ftp 服务和博客
下一篇: 谈谈自己对于 AOP 的了解
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论