• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    使用Ruby实现简单的事物驱动的web应用的教程

    简介

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

        手工编写脚本:测试人员需要知道 Web 页面上有哪些表单、输入框、选择框、按钮等,以及这些表单元素的名称,ID 等属性,然后才能利用一些工具来编写测试用例。
        通过工具录制生成:比如 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.改变购物车中书籍的数量,并且重新计算。

    业务操作

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

    领域专用语言 (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
    
    

    上面的代码非常简单,需要关注的是静态方法 execute, 当把 bookshop.txt 作为参数来调用它时,会有什么情况发生呢 ? 聪明的读者可能已经猜到了,那就是 user 和 pwd 的值会被打印出来。这段代码展示了 Ruby 语言的两个重要特点 :

        instance_eval 方法会把一段文本当做代码来执行。执行的上下文就是对象 BookshopDSLBuilder。 所以当它碰到文本 "login" 时,会自动调用真正的方法 login。
        在调用一个方法时,可以不加括号。这就是为什么 Ruby 会把文本 login "andy","pass4you" 当做一个方法调用的原因。

    这两个特点就给我们搭了一座“桥”,使得我们可以把那个面向业务测试的文本诸如“login”,“add_to_cart”,“search_book”等转化为对特定方法的调用了。我们就可以在这些方法中实现某些逻辑。
    Watir

    我们现在已经能够把业务测试的脚本和 Ruby 的对象 / 方法连接起来,可是还需要第二座桥把 Ruby 和 Web 应用程序连接起来,这样才能使业务测试的脚本驱动 Web 页面进行测试。我们希望能有一个软件或工具可以像人一样来驱动浏览器的操作,例如点击链接,填充表单,点击按钮等等。当然它也可以检查页面的结果,例如期待的文本是否出现等。

    开源工具 Watir 就是这样一个工具,除了具备上述功能外,它和 Ruby 语言还能进行无缝的集成,并且对浏览器尤其是 IE 有超强的控制能力。所以我们选取它作为第二座桥。

    下面是一个使用 watir 的简单例子,它进入 Google 的首页,在搜索框中键入 "bookshop", 然后点击"搜索"按钮。 Watir 充分继承了 Ruby 语言简单明了的特点,读者可以看到使用 Watir 的脚本是相当直观,相当容易的。
    清单 2. Watir 例子

    require "watir"
    ie = Watir::IE.new 
    ie.goto "http://www.google.com"    
    ie.text_field(:name, "q").set "bookshop"
    ie.button(:name, "btnG").click
    
    

    实现 Login

    有了上面的两座“桥”,具体的实现就简单多了,对于每一个业务操作,我们需要做的是 :

    (1) 在一个 Ruby 对象中 (BookshopDSLBuilder) 实现一个同名的方法

    (2) 在方法实现中,利用 watir 来操作界面元素。当然前提是我们需要知道界面上有哪些元素。

    先来看一看 Login 的实现:
    清单 3. Login

    class BookshopDSLBuilder 
     include Test::Unit::Assertions #include ruby unit 的 Assertion 
     def self.execute( dsl) 
      builder=new 
      builder.instance_eval(File.read(dsl), dsl) 
      builder 
     end 
     def initialize 
      @login_url = 'http://localhost:3000/bookshop/login'  #51Book 的入口
      #creat a ie instance 
      @ie= Watir::IE.new               # 创建一个 Watir 的实例
     end 
     def login(user=nil,pwd=nil) 
      @ie.goto @login_url 
      @ie.text_field(:id,"user_name").set(user)   # 设置用户名
      @ie.text_field(:id,"user_password").set(pwd)  # 设置密码
      @ie.button(:type,"submit").click        # 点击提交按钮
     end 
    end
    
    

    实现 add_to_shop_cart

    把书籍添加的购物车中这个操作相对复杂,因为它接收的参数是一个书籍的标题,而在界面上"Add to Cart"却是一个只包含 book id, 不包含标题的链接,所以无法直接定位。
    清单 4. Add to Cart

     table width='100%' class='book'> 
      tr> 
        td>title:/td> 
        td>Agile development/td> # 标题在这里
      /tr> 
      tr> 
        td>description:/td> 
        td>The book of agile development/td> 
      /tr> 
      tr> 
        td>price:/td> 
        td>30.0/td> 
      /tr> 
      tr> 
        td colspan="2"> #Add_To_Cart Link 却在这里
          a href='/bookshop/add_to_cart/1' >Add to Cart/a> 
        /td> 
      /tr>  
     /table>
    
    

    这种情况下就可以利用 Watir 对 xpath 强大的支持,先找到标题,在从标题找到链接,最后点击链接即可。
    清单 5. 使用 XPath

    def add_to_cart(title)    
      table = @ie.table(:xpath, 
         "//table[@class='book']/tbody/tr/td[text()='"+title+"']/../../../") 
      if table[1][2].text == title 
        href = table[4][1].links[1].href 
        @ie.link(:href,href).click 
      end 
    end
    
    

    对于其他的业务操作,具体的实现方式也是大同小异,这里不再一一介绍,有兴趣的读者可以参见 附件 中的代码,最后我们来看一个面向业务的 Web 页面测试例子:
    清单 6. 一个完整的例子

     login 'andy','pass4you' 
    
     add_to_cart 'Agile development'
     add_to_cart 'Savor Blue'
     add_to_cart 'Programming Ruby' 
    
     change_quantity 'Agile development',10 
     change_quantity 'Savor Blue',10 
     change_quantity 'Programming Ruby',10 
    
     recalculate_cart 
     assert_total_price_is 900 
    
     search_book 'Ant cookbook'
     add_to_cart 'Ant cookbook'
     assert_total_price_is 910
    
    

    总结

    到目前为止,我们已经通过 Ruby 完整的实现了“业务驱动” 的 Web 应用测试,实际上我们通过 Ruby 实现了一个面向业务的抽象层,利用 Watir 把业务操作映射到了对 Html 页面的操作。这样当 Html 页面发生了变化的时候,只需要调整映射,而不需要更改业务层的操作。同时由于它们是完全面向业务的,就使得开发人员或测试人员能把精力集中到业务逻辑的测试上,而不用陷入实现的细节。

    掌握了该方法以后,读者可以应用到自己的程序中,可以使得自己的测试编写简单,容易理解,易于维护。将会极大的提供 Web 应用的测试效率。

    您可能感兴趣的文章:
    • 几个加速Ruby on Rails的编程技巧
    • 利用RJB在Ruby on Rails中使用Java代码的教程
    • Ruby中数组的一些相关使用方法
    上一篇:利用RJB在Ruby on Rails中使用Java代码的教程
    下一篇:使用Ruby来编写访问Twitter的命令行应用程序的教程
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    使用Ruby实现简单的事物驱动的web应用的教程 使用,Ruby,实现,简单,的,