wangxin0072000 2009-03-20 16:29
浏览 198
已采纳

rails 单元测试

rails 如何保证每次单元测试都清理上一个测试的数据。

  • 写回答

2条回答 默认 最新

  • horace_lee 2009-03-20 19:58
    关注

    我也想弄明白这个问题,google任何rails测试机制都找不到有营养的解释
    查书后,看到一些有价值的东西
    是讲ruby的测试怎么跑的
    [code="ruby"]
    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
    [/code]
    当然,rails一定调用ruby的这个流程。
    简单讲,注册at_exit这个例程,这个kernel方法,在执行结束,执行Test::Unit::AutoRunner.run
    再相应执行:
    [code="ruby"]
    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,
    }
    [/code]

    看了这个源代码,就对ruby处理单元测试,大体了解。那么想知道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是我们要找的,需要加载数据的那个
    继续读有如下方法:
    [code="ruby"]
    Methods

    * included
    * run_in_transaction?
    * setup_fixtures
    * teardown_fixtures
    

    [/code]

    继续读,就清楚多了,一个加载环境,一个回滚。所以,理论上讲如果,你不想加载数据,也可以从这里修改。
    [code="ruby"]
    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
    

    [/code]

    [code="ruby"]
    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
    

    [/code]

    [code="ruby"]
    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
    

    [/code]

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 r语言蛋白组学相关问题
  • ¥15 Python时间序列如何拟合疏系数模型
  • ¥15 求学软件的前人们指明方向🥺
  • ¥50 如何增强飞上天的树莓派的热点信号强度,以使得笔记本可以在地面实现远程桌面连接
  • ¥20 双层网络上信息-疾病传播
  • ¥50 paddlepaddle pinn
  • ¥20 idea运行测试代码报错问题
  • ¥15 网络监控:网络故障告警通知
  • ¥15 django项目运行报编码错误
  • ¥15 STM32驱动继电器