论坛首页 编程语言技术论坛

Rails UnitTest 测试机制浅析

浏览 3432 次
精华帖 (2) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-03-20   最后修改:2009-03-20
    一直以来,都想知道,Rails在进行UnitTest的时候,是怎么处理数据的。怎么保证单元测试结束后,可以清除上一个测试的数据的。今天,稍微有时间就借着一位老大的问题,浅浅的探究了一下,理解不对的地方大家指正。

首先,应该弄明白Ruby的测试怎么跑的,因为很显然
module ActiveSupport
  class TestCase < Test::Unit::TestCase

Rails的ActiveSupport调用了Ruby的测试。那么,找到Ruby当前目录的test/unit下看看怎么运行的。

  module Unit
    # If set to false Test::Unit will not automatically run at exit.
    def self.run=(flag)
      @run = flag
    end

    # Automatically run tests at exit?
    def self.run?
      @run ||= false
    end
  end
end

at_exit do
  unless $! || Test::Unit.run?
    exit Test::Unit::AutoRunner.run
  end
end



当然,rails一定调用ruby的这个流程。
简单讲,注册at_exit这个例程,这个kernel方法,在执行结束,执行Test::Unit::AutoRunner.run
在找到对应代码的,对应部分,会看到如下执行:

      RUNNERS = {
        :console => proc do |r|
          require 'test/unit/ui/console/testrunner'
          Test::Unit::UI::Console::TestRunner
        end,
        :gtk => proc do |r|
          require 'test/unit/ui/gtk/testrunner'
          Test::Unit::UI::GTK::TestRunner
        end,
        :gtk2 => proc do |r|
          require 'test/unit/ui/gtk2/testrunner'
          Test::Unit::UI::GTK2::TestRunner
        end,
        :fox => proc do |r|
          require 'test/unit/ui/fox/testrunner'
          Test::Unit::UI::Fox::TestRunner
        end,
        :tk => proc do |r|
          require 'test/unit/ui/tk/testrunner'
          Test::Unit::UI::Tk::TestRunner
        end,
      }



看了这个源代码,就对ruby处理单元测试,大体了解,这很好的说明,为什么Rails里的UnitTest根本不写执行,就写一堆def就行了。
那么想知道Rails对数据库怎么处理的那得继续看相应的看源代码了
于是,找到rubyonrails的api看到相应的类
Class
ActiveSupport::TestCase
In: 
vendor/rails/railties/lib/test_help.rb 
vendor/rails/activesupport/lib/active_support/test_case.rb

下面有
    * ActiveRecord::TestFixtures
    * Rails::BacktraceFilterForTestUnit
    * ActiveSupport::Testing::Default
    * ActiveSupport::Testing::SetupAndTeardown
    * ActiveSupport::Testing::Assertions
    * ActiveSupport::Testing::Deprecation


而ActiveRecord::TestFixtures是我们要找的,需要加载数据的那个
现在,看还挺理所当然的,当时,可是看了好多源码才确定这个文件的部分,才是导致数据加载的部分。
继续读有如下方法:

Methods

    * included
    * run_in_transaction?
    * setup_fixtures
    * teardown_fixtures



再看几个代码就清楚多了,一个加载环境,一个回滚。所以,理论上讲如果,你不想加载数据,也可以从这里修改。


     def self.included(base)
       base.class_eval do
         setup :setup_fixtures
         teardown :teardown_fixtures
 
         superclass_delegating_accessor :fixture_path
         superclass_delegating_accessor :fixture_table_names
         superclass_delegating_accessor :fixture_class_names
         superclass_delegating_accessor :use_transactional_fixtures
         superclass_delegating_accessor :use_instantiated_fixtures   # true, false, or :no_instances
         superclass_delegating_accessor :pre_loaded_fixtures
 
         self.fixture_table_names = []
         self.use_transactional_fixtures = false
         self.use_instantiated_fixtures = true
         self.pre_loaded_fixtures = false
 
         self.fixture_class_names = {}
       end
 
       base.extend ClassMethods
     end





     def setup_fixtures
       return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
 
       if pre_loaded_fixtures && !use_transactional_fixtures
         raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
       end

      @fixture_cache = {}
       @@already_loaded_fixtures ||= {}
 
       # Load fixtures once and begin transaction.
       if run_in_transaction?
         if @@already_loaded_fixtures[self.class]
           @loaded_fixtures = @@already_loaded_fixtures[self.class]
        else
          load_fixtures
           @@already_loaded_fixtures[self.class] = @loaded_fixtures
        end
         ActiveRecord::Base.connection.increment_open_transactions
         ActiveRecord::Base.connection.transaction_joinable = false
        ActiveRecord::Base.connection.begin_db_transaction
       # Load fixtures for every test.
       else
         Fixtures.reset_cache
         @@already_loaded_fixtures[self.class] = nil
         load_fixtures
       end
 
      # Instantiate fixtures for every test if requested.
       instantiate_fixtures if use_instantiated_fixtures
     end


哈,这就是我一直想找的代码,而且,注释写的太直接了。每次测试加载一次Fixture


下面是回滚的部分:

     def teardown_fixtures
       return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
       unless run_in_transaction?
         Fixtures.reset_cache
       end
 
       # Rollback changes if a transaction is active.
       if run_in_transaction? && ActiveRecord::Base.connection.open_transactions != 0
         ActiveRecord::Base.connection.rollback_db_transaction
         ActiveRecord::Base.connection.decrement_open_transactions
      end
       ActiveRecord::Base.clear_active_connections!
     end



   发表时间:2009-03-20  
赞!
grep "Load fixtures" *.rb

0 请登录后投票
   发表时间:2009-05-23  
我刚开始接触测试的时候 发现Fixture加载的只有三组数据 每次测试的时候发现test数据库一直都是三条记录 而不是一直累积上去。 原来是因为这个 O.O
0 请登录后投票
   发表时间:2009-06-03  
rails 2.3的test/fixtures下文件不自动加载?在哪里设置呀?
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics