rails的fixtures有一个令人讨厌的地方:
fixtures 的数据不会在测试结束后自动清除 ,这样就使得fixtures遗留的数据影响到后来的测试。
相关的争论也持续了很久 ,具体的连接请看 http://dev.rubyonrails.org/ticket/2404
里面的 Rick的patch我在rspec下用了,不见好用,我只能自己搞了一个patch,在rspec的 spec_helper.rb下引入
,解决了这个问题 。
patch主要的思路是: 每次测试setup运行前插入fixture的数据,保证这个插入 fixtures数据的事务和test运行时的事务是同一个 ,teardown结束前,清空一些类变量, 原有的teardown运行的时候会作事务回滚的动作,这样就可以保证每次测试都回滚圆来插入的 fixtures的数据。
相关的配置 :
[code]
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false[/code]
[code]
module Test #:nodoc:
module Unit #:nodoc:
class TestCase #:nodoc:
alias_method : old_setup_with_fixtures, :setup_with_fixtures unless method_defined?(: old_setup_with_fixtures)
alias_method : old_teardown_with_fixtures, :teardown_with_fixtures unless method_defined?(: old_teardown_with_fixtures)
def setup_with_fixtures
if use_transactional_fixtures?
ActiveRecord::Base.send :increment_open_transactions
ActiveRecord::Base.connection.begin_db_transaction
close_original_activerecord_transaction_methods
end
old_setup_with_fixtures
if use_transactional_fixtures?
open_original_activerecord_transaction_methods
end
end
def teardown_with_fixtures
if use_transactional_fixtures?
clear_fixtures_states_when_use_transactional_fixtures
end
old_teardown_with_fixtures
end
#prevent the next code:alias_method from trigger invoking the self.method_added introspected method
class<<TestCase
alias old_method_added method_added
def method_added(m)
#do nothing
end
end
alias_method :setup,:setup_with_fixtures
alias_method :teardown,:teardown_with_fixtures
#reopen the introspector class method:method_added
class<<TestCase
alias method_added old_method_added
end
private
def clear_fixtures_states_when_use_transactional_fixtures
@@already_loaded_fixtures.clear if @@already_loaded_fixtures
@loaded_fixtures.clear if @loaded_fixtures
end
def close_original_activerecord_transaction_methods
self.class.class_eval(%Q[
class<<ActiveRecord::Base
alias old_increment_open_transactions increment_open_transactions
def increment_open_transactions
#do nothing
end
end
])
ActiveRecord::Base.connection.class.class_eval(%Q[
alias_method : old_begin_db_transaction,:begin_db_transaction
def begin_db_transaction
#do nothing
end
])
end
def open_original_activerecord_transaction_methods
self.class.class_eval(%Q[
class<<ActiveRecord::Base
alias increment_open_transactions old_increment_open_transactions
end
])
ActiveRecord::Base.connection.class.class_eval(%Q[
alias_method :begin_db_transaction,: old_begin_db_transaction
])
end
end
end
end
[/code]
fixtures 的数据不会在测试结束后自动清除 ,这样就使得fixtures遗留的数据影响到后来的测试。
相关的争论也持续了很久 ,具体的连接请看 http://dev.rubyonrails.org/ticket/2404
里面的 Rick的patch我在rspec下用了,不见好用,我只能自己搞了一个patch,在rspec的 spec_helper.rb下引入
,解决了这个问题 。
patch主要的思路是: 每次测试setup运行前插入fixture的数据,保证这个插入 fixtures数据的事务和test运行时的事务是同一个 ,teardown结束前,清空一些类变量, 原有的teardown运行的时候会作事务回滚的动作,这样就可以保证每次测试都回滚圆来插入的 fixtures的数据。
相关的配置 :
[code]
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false[/code]
[code]
module Test #:nodoc:
module Unit #:nodoc:
class TestCase #:nodoc:
alias_method : old_setup_with_fixtures, :setup_with_fixtures unless method_defined?(: old_setup_with_fixtures)
alias_method : old_teardown_with_fixtures, :teardown_with_fixtures unless method_defined?(: old_teardown_with_fixtures)
def setup_with_fixtures
if use_transactional_fixtures?
ActiveRecord::Base.send :increment_open_transactions
ActiveRecord::Base.connection.begin_db_transaction
close_original_activerecord_transaction_methods
end
old_setup_with_fixtures
if use_transactional_fixtures?
open_original_activerecord_transaction_methods
end
end
def teardown_with_fixtures
if use_transactional_fixtures?
clear_fixtures_states_when_use_transactional_fixtures
end
old_teardown_with_fixtures
end
#prevent the next code:alias_method from trigger invoking the self.method_added introspected method
class<<TestCase
alias old_method_added method_added
def method_added(m)
#do nothing
end
end
alias_method :setup,:setup_with_fixtures
alias_method :teardown,:teardown_with_fixtures
#reopen the introspector class method:method_added
class<<TestCase
alias method_added old_method_added
end
private
def clear_fixtures_states_when_use_transactional_fixtures
@@already_loaded_fixtures.clear if @@already_loaded_fixtures
@loaded_fixtures.clear if @loaded_fixtures
end
def close_original_activerecord_transaction_methods
self.class.class_eval(%Q[
class<<ActiveRecord::Base
alias old_increment_open_transactions increment_open_transactions
def increment_open_transactions
#do nothing
end
end
])
ActiveRecord::Base.connection.class.class_eval(%Q[
alias_method : old_begin_db_transaction,:begin_db_transaction
def begin_db_transaction
#do nothing
end
])
end
def open_original_activerecord_transaction_methods
self.class.class_eval(%Q[
class<<ActiveRecord::Base
alias increment_open_transactions old_increment_open_transactions
end
])
ActiveRecord::Base.connection.class.class_eval(%Q[
alias_method :begin_db_transaction,: old_begin_db_transaction
])
end
end
end
end
[/code]