ensaios e establish_connection
Pergunta
Como faço para escrever testes para projetos que establish_connection
uso em modelo para se conectar a outro banco de dados?
Solução
Quando você faz establish_connection para determinados modelos para conectar a um banco de dados diferente, um do problema que iria enfrentar ao testar essas tabelas é que os dados de teste que você criou não vai ser revertida automaticamente.
O código real para criar uma transação Save Point e para reverter os dados de vida de teste em rails/activerecord/lib/active_record/fixtures.rb
. E, especialmente, existem dois métodos setup_fixtures
e teardown_fixtures
. O código nesses métodos são para a frente. Eles simplesmente criar um ponto de salvamento e faz rollback para cada teste. Mas isso não apenas para a conexão ActiveRecord::Base
.
Então, o que você tem a fazer é "monkey patch" estes métodos de modo que, além da conexão ActiveRecord::Base
, o mesmo conjunto de operações são feitas para a sua conexão de banco de dados adicional.
Aqui está um código de exemplo para o mesmo:
## database.yml
development:
database: dev
test:
database: test
#...
my_connection_development:
database: my_connection_dev
my_connection_test:
database: my_connection_test
#...
## my_connection_base.rb
class MyConnectionBase < ActiveRecord::Base
establish_connection(ActiveRecord::Base.configurations["my_connection_#{RAILS_ENV}"])
self.abstract_class = true
end
## my_model.rb
class MyModel < MyConnectionBase
end
## my_another_model.rb
class MyAnotherModel < MyConnectionBase
end
## test_case_patch.rb
module ActiveSupport
class TestCase
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
MyConnectionBase.connection.increment_open_transactions
MyConnectionBase.connection.transaction_joinable = false
MyConnectionBase.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
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? && MyConnectionBase.connection.open_transactions != 0
MyConnectionBase.connection.rollback_db_transaction
MyConnectionBase.connection.decrement_open_transactions
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
MyConnectionBase.clear_active_connections!
ActiveRecord::Base.clear_active_connections!
end
end
end
Outras dicas
Eu não vejo a necessidade de alterar os códigos de teste depois de colocar establish_connection no seu modelo desde que você ainda testar a mesma funcionalidade do modelo.
Você não vai precisar para testar o método establish_connection, como um método activrecord e está bem testado, antes do lançamento.
embora se você ainda quiser fazê-lo, chame o método dentro de um método diferente, e veja se você pode se conectar a tabelas apropriadas em que a DB.