(一)Ruby on Rails 中的测试策略

发表于:2007-12-17 17:38

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:网络转载

  在 Rails on Rails 社区,执行测试是必不可少的。从用于处理覆盖率的 Rails 堆栈和 RCov 到用于增强测试用例的 Mocha 和 FlexMock,现在已经有很多工具可用。但不同的工具通常支持不同的策略。通过本文,了解这些基础测试策略的利弊权衡。
  Rails 平台的独特之处就是 Ruby 语言本身。做为动态类型语言,Ruby 有很强的灵活性、方便性和功能性,但这些优点是有代价的。动态类型语言没有能捕捉某些错误(包括相对常见的输入错误和一些拼写错误)的编译器。从很早开始,面向对象的动态类型语言的用户就知道他们必须要进行测试。

  Ruby on Rails 社区对测试的拥护程度就像美国人对 American Idol 节目的热衷一样。他们会定期查看测试用例结果。Ruby 的开发人员时常会谈及测试、将测试在 blog 上大书特书,有时甚至在幕后参与:参与的方式多是通过为开源框架做贡献,这与选 American Idol 通过手机投票进行参与的方式不同。

  没有测试,Ruby 应用程序每行代码的出错率要比有测试的情况高很多。有了测试,您就能享有动态类型语言的诸多益处,而不利之处则更少。在本篇文章中,我不想谈论那些您已经十分熟悉的基本知识,比如是否需要测试或怎样才能说服经理让他认可测试是值得的。(我假设您进行过测试。)与之相反,我会对每个 Ruby 项目主管最终都必须要做的一些微妙的测试决定详加介绍。我会谈及如何测量测试覆盖率以及究竟应该进行多少测试。此外,我还会讲解基础的开箱即用的测试技术以及它们与新的 mock 框架相比孰优孰劣。与提供一个包罗万象的教程相反,我带给您的是一些我们在构建 ChangingThePresent.org(请参阅 参考资料)时所使用的技术的示例,以便您能对这些技术有一个基本认识。此外我还会详细地分析各种技术的优缺点。

开箱即用的 Rails 测试

  在添加单个的 gem 前,Rail 框架所具有的测试异常健壮。只需很少的操作,就能指定可重复的数据库设置、向 Web 应用程序发送模拟的 HTTP 消息,并能进行三种测试:单元测试功能测试和集成测试。下一节给出了这些测试的简单例子。

单元测试

  单元测试针对的是 Rails 模型代码,有时还包括帮助器。单元测试用于确保模型能够按其构建之初的目标工作和确保模型中的关联能按预期运转。您应该还记得,Rails 模型是包装单一数据库表的对象。大多数情况下,每个数据库列都是具体某个模型上的一个属性。Rails 帮助器是帮助简化模型、视图、控制器代码的函数。需要确保每个模型或帮助器都有测试。在 ChangingThePresent,我们为最基础的模型而做的单元测试不多。


清单 1. 一个基础模型测试
   require File.dirname(__FILE__) + '/../test_helper'

class BannerStyleTest < Test::Unit::TestCase
  fixtures :banner_styles

  def test_associations
    assert_working_associations
  end

  def test_validation_with_incorrect_specs_should_fail
    bs =  BannerStyle.new(:height => 10, :width => 10, :format => 'vertical_rectangle',
                          :model_name => 'Nonprofit')
    assert !bs.save, bs.errors.inspect

    bs2 =  BannerStyle.new(:height => 400, :width => 240, :format => 'vertical_rectangle',
                          :model_name => 'Nonprofit')
    assert bs2.save, bs2.errors.inspect
  end

  ...
end
 
清单 1 中所示的是具有两个测试的浓缩测试用例。Banner_styles 创建简单的广告横幅。每个横幅的大小和形状都基于一组松散的标准。此应用程序使用一个包含这些标准的表确保任何一个新横幅都符合这些标准。第一个测试使用帮助器通过反射检验 BannerStyle 上的所有关联,如清单 2 所示。第二个测试确保高和宽不符合标准的横幅不被保存,具有有效规格的横幅则被正确保存。


清单 2. 用于测试有效关联的帮助器
               
def assert_working_associations(m=nil)
  m ||= self.class.to_s.sub(/Test$/, '').constantize
  @m = m.new
  m.reflect_on_all_associations.each do |assoc|
    assert_nothing_raised("#{assoc.name} caused an error") do
      @m.send(assoc.name, true)
    end
  end
  true
end
 


清单 2 显示了能检验一个类中所有关联的帮助器。assert_working_associations 方法遍历此类上的所有关联并将关联的名称发送给该模型。这种 “一网打尽” 的做法能确保用每个模型使用一行代码即可调用所有模型测试中存在的关系。

功能和集成测试

功能测试通过孤立的 HTTP 请求检验用户接口。Rails 框架很利于调用单一 HTTP GET 和 POST 命令,是这类测试的骨干。集成测试也一样,但它们能一个接一个的调用很多 HTTP 请求。这类测试的原理和结构大都相同。清单 3 给出了一些基础的功能测试。


清单 3. 一个简单的功能测试
  require File.dirname(__FILE__) + '/../test_helper'
require 'causes_controller'

class CausesController; def rescue_action(e) raise e end; end

class CausesControllerTest < Test::Unit::TestCase
  fixtures :causes, :members, :quotes, :cause_images, :blogs, :blog_memberships

  def setup
    @controller = CausesController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end

  def test_index
    get :index

    assert_response :success
    assert_template 'index'

    assert_not_nil assigns(:causes)
    assert_equal Cause.find_all_ordered.size, assigns(:causes).size
  end

  def test_should_create_blog
    assert Cause.find(2).blog.nil?
    get :create_blog, :id => 2
    assert Cause.find(2).blog.nil?

    login_as :bruce
    get :create_blog, :id => 2
    assert !Cause.find(2).blog.nil?
    assert_equal Cause.find(2).name, Cause.find(2).blog.title
  end
 

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号