验收测试(Acceptance Testing),是确认应用是否满足用户需求的测试。这种测试往往是站在用户的角度,看整个应用能否满足业务需求。从名字上来看,验收应该是业务人员的事,但业务人员能做的最多只是验收,测试这件事,往往还是由技术团队自己完成,而且在很多公司,这就是测试人员的事。
时至今日,很多测试团队都拥有自动化的能力。验收测试是人们最早想到的自动化测试,早在单元测试还不流行的年代,人们就开始了对自动化验收测试的探索。有不少团队甚至还构建了自己的框架,只不过,这种框架不是我们今天理解的测试框架,而是针对着一个应用的测试框架。
让验收测试从各自为战的混乱中逐渐有了体系的是行为驱动开发(Behavior Driven Development)这个概念的诞生,也就是很多人知道的 BDD。
行为驱动开发中的行为,指的是业务行为。BDD 希望促进业务人员与开发团队之间的协作,换句话说,如果想做BDD,就应该用业务语言进行描述。这与我们传统上理解的系统测试有着很大的差别,传统意义上的系统测试是站在开发团队的角度,所以,更多的是在描述系统与外部系统之间的交互,用的都是计算机的术语。
而BDD 则让我们换了一个视角,用业务语言做系统测试,所以,它是一个更高级别的抽象。
BDD 是 2003 年由 Dan North 提出了来的。Dan North 不仅仅提出了概念,为了践行他的想法,他还创造了第一个 BDD 的框架:JBehave。后来又改写出基于Ruby的版本 RBehave,这个项目后来被并到RSpec中。
今天最流行的BDD 框架应该是Cucumber,它的作者就是RSpec 的作者之一 Aslak Hellesøy。
Cucunber 从最开始的 Ruby BDD 框架发展成今天支持很多不同程序设计语言的 BDD 测试框架,比如,常见的 Java、JavaScript、PHP 等等。
BDD 框架给我们最直观的感受就是它给我们提供的一套语言体系,供我们描述应用的行为,下面是一个例子,它描述了一个交易场景,应用需要根据交易结果判定是否要发出警告:
Scenario: trader is not alerted below threshold
Given a stock of symbol STK1 and a threshold of 10.0
When the stock is traded at 5.0
Then the alert status should be OFF
Scenario: trader is alerted above threshold
Given a stock of symbol STK1 and a threshold of 10.0
When the stock is traded at 11.0
Then the alert status should be ON
我们在这里的关注点是这个例子的样子,首先是描述格式:“Given…When…Then”,这个结构对应着这个测试用例中的执行步骤。Given 表示的一个假设前提,When 表示具体的操作,Then 则对应着这个用例要验证的结果。
常见的测试结构包含四个部门,前置准备、执行、断言和清理,这刚好与“Given…When…Then”做一个对应,Given 对应前置条件,When 对应执行,Then 则对应着断言。至于清理,它会做一些资源释放,属于实现层面的内容,在业务层面上意义不大。
了解了格式,我们还要关心一下内容。这里描述的行为都是站在业务的角度进行叙述的,而且Given、When、Then 都是独立的,可以自由组合。也就是说,一旦基础框架搭好了,我们就可以用这些组成块来编写新的测试用例,甚至可以不需要技术人员参与。
不过,这些内容都是站在业务角度的描述,没有任何实现的内容,那实现的内容放在哪呢?
我们还需要定义一个胶水层,把测试用例与实现联系起来的胶水层,在Cucumber 的术语里,称之为步骤定义(Step Definition)。这里给出了一个例子,可以参考一下:
public class TraderSteps implements En {
private Stock stock;
public TraderSteps() {
Given("^a stock of symbol {string} and a threshold of {double}", (String symbol, double threshold) -> {
stock = new Stock(symbol, threshold);
});
When("^the stock is traded at {double}$", (double price) -> {
stock.tradeAt(price);
});
Then("the alert status should be {string}", (String status) -> {
assertThat(stock.getStatus().name()).isEqualTo(status);
})
}
}
写好验收测试用例
有了对BDD 框架的基本了解,接下来的问题就是,怎么用好 BDD 框架。我们举个简单的例子,如果我们要写一个登录的测试用例,会怎么写呢?
可以这样写:
假定张三是一个注册用户,其用户名密码是分别是zhangsan 和 zspassword
当在用户名输入框里输入zhangsan,在密码输入框里输入 zspassword
并且点击登录
那么张三将登录成功
这个用例怎么样呢?这个用例是站在程序员的视角。而BDD 需要站在业务的角度,这个例子完全是站在实现的角度。
如果登录方式有所调整,用户输完用户名密码自动登录,不需要点击,那这个用例是不是需要改呢?下面换一种方式描述,再感受一下:
假定张三是一个注册用户,其用户名密码是分别是zhangsan 和 zspassword
当用户以用户名zhangsan 和密码 zspassword 登录
那么张三将登录成功
这是一个站在业务视角的描述,除非做业务的调整,不用用户名密码登录了,否则,这个用例不需要改变,即便实现的具体方式调整了,需要改变的也是具体的步骤定义。
所以,想写好BDD 的测试用例,关键点在用业务视角描述。
编写验收测试用例的步骤定义时,还有一个人们经常忽略的点:业务测试的模型。很多人的第一直觉是,一个测试要啥模型?好测试应该具备的属性呢?其中一点就是Professional,专业性。想要写好测试,同写好代码是一样的,一个好的模型是不可或缺的。
这方面一个可以参考的例子是,做Web 测试常用的一个模型:Page Object。它把对页面的访问封装了起来,即便写的是步骤定义,也不应该在代码中直接操作HTML 元素,而是应该访问不同的页面对象。
以前面的登录为例,我们可能会定义这样的页面对象:
public class LoginPage {
public boolean login(String name, String password) {
...
}
}
如此一来,在步骤定义中,就不必关心具体怎么定位到输入框,会让代码的抽象程度得到提升。
当然,这只是一个参考,面对不同的应用,需要构建自己的业务测试模型。
网友评论