使用 Ruby 实现业务驱动的 Web 应用程序测试

来源:developerWorks 中国 作者:刘 欣
  
自动化的 Web 集成测试对于保证软件质量是很有效的,但是编写和维护这些测试用例却不是一件容易的事。本文介绍的是一种利用 Ruby 实现业务驱动的集成测试方法, 通过该方法,读者能够脱离复杂的技术细节,把注意力集中到业务逻辑的测试中来。

简介

对 Web 应用程序来讲,自动化的集成测试是一个非常重要的部分, 然而由于这些测试用例太依赖具体的 Web 页面的实现细节,这就给编写和维护带来的很大的挑战。 通常来讲有两种方法可以生成 Web 应用程序测试用例。

  1. 手工编写脚本:测试人员需要知道 Web 页面上有哪些表单、输入框、选择框、按钮等,以及这些表单元素的名称,ID 等属性,然后才能利用一些工具来编写测试用例。
  2. 通过工具录制生成:比如 IBM Rational Functional Tester 就提供了录制用户在 Web 界面的操作,自动生成测试用例的功能。

方法 1 需要测试人员了解太多的 Web 页面细节,这就使得测试人员不能把精力集中在业务逻辑上,一旦 Web 页面发生变化,将不得不花费大量精力更新脚本。方法 2 能够自动生成测试脚本,但是这些脚本的可读性很差,导致很难维护。同样如果 Web 页面发生变化,测试人员也需要重新录制所有的脚本。

那么有没有办法克服上述问题,让工作更加轻松一点呢?答案是肯定的!

例如一个在线的电子书店,对于用户购书的场景,我们可以用下面的脚本来进行集成测试 :

login 'test@test.com','pass4you'     // 登录 
list_books                           // 列出书籍 
add_to_shop_cart  '谁说大象不能跳舞'  // 把《谁说大象不能跳舞》这本书加入到购物车中
       

读者可以看到, "login" , "list_books", "add_to_shop_cart" 这些术语已经完全脱离了具体的页面细节,将不会受到页面变化的影响, 它们是完全面向业务的,准确的体现了应用的业务逻辑,容易理解、易于维护,并且还能拿来和业务人员进行交流,甚至业务人员自己都能编写测试脚本。 有这么多的优点,那么如何实现它们呢?这正是本文要介绍的重点:利用动态语言 Ruby 来实现“业务驱动”的 Web 应用测试。

Ruby 介绍

Ruby,中文意思为红宝石,但是在计算机领域,它代表一种相当优秀的面向对象的脚本程序语言。它诞生于 1993 年,近年来随着 Ruby on Rails 这个“Killer application”在 Web 开发领域迅速蹿红。Ruby 在最初设计时吸收了很多别的语言的精华,例如 perl 语言的文本处理能力,Python 语言的简单性和可读性,以及方便的扩展能力和强大的可移植能力,Smalltalk 语言的纯面向对象语法思想,这就使它具备了很多其他语言的优点。Ruby 的设计理念是尽量减少编程时不必要的琐碎工作,让程序员在完成任务的同时充分的享受编程的乐趣。

Ruby 的特点如下:

  • 面向对象:在 Ruby 中,一切皆是对象,包括其他语言中的基本数据类型,比如整数。

    例如在 Java 中,对一个数求绝对值用 Math.abs(-20), 但在 Ruby 中一切皆对象,-20 这个数也是对象,所以可以这么做 -20.abs , 是不是更加形象和直观?

  • 解释型脚本语言:无需编译,直接执行,开发周期短,调试方便。
  • 动态性:已经定义的类可以在运行时修改。

本文的重点不是介绍 Ruby 语言本身,有兴趣的读者可以参见 参考资源 部分。

案例分析

51book

为了展示如何使用 Ruby 进行业务驱动的测试,同时又不让读者陷入到过多细节中,本文假想了一个简单的在线购书应用 ( 简称 51book),这个应用支持如下主要功能:

  1. 登录 : 用户必须登录才能购买书籍。

    图 1. 登录
    登录

  2. 浏览书籍:包括按标题搜索书籍。

    图 2. 浏览和搜索书籍
    浏览书籍

  3. 把书籍添加到购物车中,参见 图 2 中的“Add to cart”链接。
  4. 改变购物车中书籍的数量,并且重新计算。

    图 3. 购物车
    购物车

业务操作

通过上面的介绍,读者应该对 51book 有了一个简单的了解,接下来我们考虑如何进行业务驱动的测试,首先需要定义面向业务的操作,这样才能在测试用例中使用它们。 简单起见,我们定义如下业务操作:


表 1. 业务操作
业务操作 功能说明
login "user_name", "password" 该操作接受用户名和密码,触发在 Web 界面的登录
add_to_shop_cart "book_title" 该操作接受一个书籍名称为参数,可以把当前页面的该书籍加入到购物车中
search_book "book_title" 该操作以书籍名称为参数来搜索书籍
change_quantity "book_title" 该操作改变一本书在购物车中的数量
recalculate_cart "book_title" 该操作在改变了购物车中的内容后,可以重新计算总价格
assert_total_price_is "price" 该操作实际上是个断言 (Assert), 它被用来 Assert 购物车中的总价格和测试人员的期待是相符的




领域专用语言 (Domain Specific Language)

所谓领域专用语言(domain specific language / DSL),其基本思想是“求专不求全”,不像通用目的语言那样目标范围涵盖一切软件问题, 而是专门针对某一特定问题的计算机语言。正如它的名称所宣称的那样,这种语言并不是通用的,只是专注于某个特定的“领域”, 例如 SQL 语言就是数据库的 DSL,使用 SQL 可以完成各种各样数据的操作,而不用关心底层的具体数据库实现。由于“领域专用”,你想用 SQL 来开发一个桌面应用程序是不可能的。

我们在上一节定义的 login , add_to_shop_cart , change_quantity 就是针对 51book 在线书店的 DSL。

Martin Fowler 把 DSL 分为两大类:外部 DSL 和内部 DSL。对外部 DSL 来讲,构建它需要做的是:(1) 定义面向领域的全新的语法。(2) 用某种语言编写解释器或编译器 ,由于这种语言是全新的,我们有很多工作需要做;那么对于内部 DSL 来说,我们可以选定一种灵活的语言,选取它一个语法的子集,并且利用这种语言的动态特性进行定制,这样就避免了重新打造一个全新语言的庞大工作量。

Ruby 语言具备非常丰富的语法和异常灵活的动态特征,非常适合创建动态 DSL。本文就是利用 Ruby 来创建 51book 面向测试的 DSL。





用 Ruby DSL 实现业务操作

原理

由于 Ruby 是一种动态脚本语言,是解释执行的,它提供了对一段文本进行 “evaluate”执行的方法。也就是说,我们可以提供一段文本(不必是完整的程序),Ruby 就可以在一个特定的上下文中执行它,当然这段文本需要符合 Ruby 的语法。

比如我们有一个文件 bookshop.txt,它包含了如下文本 : login "andy", "pass4you" , 那么怎么执行它呢?首先需要一个上下文,我们可以定义一个类来表示:


清单 1. BookshopDSLBuilder
				 
class BookshopDSLBuilder   
    def self.execute( dsl) 
        builder=new 
        builder.instance_eval(File.read(dsl), dsl)    
    end  
    def login(user=nil,pwd=nil) 
        print user 
        print pwd 
    end 
end 
       

上面的代码非常简单,需要关注的是静态方法


时间:2009-08-04 09:38 来源:developerWorks 中国 作者:刘 欣 原文链接

好文,顶一下
(1)
100%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量