specs for multi orms/connections and some implementation

This commit is contained in:
Jon Rowe 2010-03-30 22:49:30 +01:00
parent ebb6377fe5
commit f7858cd501
3 changed files with 352 additions and 103 deletions

View file

@ -38,6 +38,45 @@ module DatabaseCleaner
end
class << self
def [](orm)
raise NoORMDetected if orm.nil?
DatabaseCleaner::Base.new(orm)
end
def connections
@connections ||= [::DatabaseCleaner::Base.new]
end
def strategy=(stratagem)
self.connections.first.strategy = stratagem
end
def orm=(orm)
self.connections.first.orm = orm
end
def start
self.connections.first.start
end
def clean
self.connections.first.clean
end
def clean_with(stratagem)
self.connections.first.clean_with stratagem
end
end
class Base
def initialize(desired_orm = nil)
if desired_orm == :autodetect || desired_orm.nil?
autodetect
else
self.orm = desired_orm
end
end
def create_strategy(*args)
strategy, *strategy_args = args
@ -63,8 +102,8 @@ module DatabaseCleaner
end
end
def orm=(orm_string)
@orm = orm_string
def orm=(desired_orm)
@orm = desired_orm
end
def start
@ -77,6 +116,14 @@ module DatabaseCleaner
alias clean! clean
def orm
@orm || autodetect
end
def auto_detected
return true unless @autodetected.nil?
end
private
def strategy
@ -84,44 +131,46 @@ module DatabaseCleaner
raise NoStrategySetError, "Please set a strategy with DatabaseCleaner.strategy=."
end
def orm_module
::DatabaseCleaner.orm_module(orm)
end
def orm_strategy(strategy)
require "database_cleaner/#{orm}/#{strategy}"
require "database_cleaner/#{orm.to_s}/#{strategy.to_s}"
orm_module.const_get(strategy.to_s.capitalize)
rescue LoadError => e
raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM! Available strategies: #{orm_module.available_strategies.join(', ')}"
end
def orm
def autodetect
@orm ||= begin
@autodetected = true
if defined? ::ActiveRecord
'active_record'
:active_record
elsif defined? ::DataMapper
'data_mapper'
:data_mapper
elsif defined? ::MongoMapper
'mongo_mapper'
:mongo_mapper
elsif defined? ::CouchPotato
'couch_potato'
:couch_potato
else
raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, MongoMapper or CouchPotato loaded?"
end
end
end
def orm_module
case orm
when 'active_record'
when :active_record
DatabaseCleaner::ActiveRecord
when 'data_mapper'
when :data_mapper
DatabaseCleaner::DataMapper
when 'mongo_mapper'
when :mongo_mapper
DatabaseCleaner::MongoMapper
when 'couch_potato'
when :couch_potato
DatabaseCleaner::CouchPotato
end
end
end
end

View file

@ -19,76 +19,190 @@ describe DatabaseCleaner do
end
end
# These examples muck around with the constants for autodetection so we need to clean up....
before(:all) do
TempAR = ActiveRecord unless defined?(TempAR)
TempMM = MongoMapper unless defined?(TempMM)
Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper)
# need to add one for each ORM that we load in the spec helper...
context "orm specification" do
it "should not accept unrecognised orms" do
lambda { ::DatabaseCleaner[nil] }.should raise_error ::DatabaseCleaner::NoORMDetected
end
after(:all) do
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord) #want to make sure we have the real one...
ActiveRecord = TempAR
MongoMapper = TempMM
it "should accept :active_record" do
cleaner = ::DatabaseCleaner[:active_record]
cleaner.should be_a ::DatabaseCleaner::Base
cleaner.orm.should == :active_record
end
it "should accept :data_mapper" do
cleaner = ::DatabaseCleaner[:data_mapper]
cleaner.should be_a ::DatabaseCleaner::Base
cleaner.orm.should == :data_mapper
end
it "should accept :mongo_mapper" do
cleaner = ::DatabaseCleaner[:mongo_mapper]
cleaner.should be_a ::DatabaseCleaner::Base
cleaner.orm.should == :mongo_mapper
end
it "should accept :couch_potato" do
cleaner = ::DatabaseCleaner[:couch_potato]
cleaner.should be_a ::DatabaseCleaner::Base
cleaner.orm.should == :couch_potato
end
end
context "class methods" do
it "should have array of connections (orm agnostic)" do
::DatabaseCleaner.connections.should respond_to(:each)
end
it "should give me a default (autodetection) databasecleaner by default" do
::DatabaseCleaner.connections.should have (1).items
::DatabaseCleaner.connections.first.should be_a ::DatabaseCleaner::Base
end
end
context "instance methods" do
it "should default to autodetect upon initalisation" do
cleaner = ::DatabaseCleaner::Base.new
cleaner.auto_detected.should == true
end
context "autodetect" do
before(:all) do
Temp_AR = ActiveRecord if defined?(::ActiveRecord) and not defined?(Temp_AR)
Temp_DM = DataMapper if defined?(::DataMapper) and not defined?(Temp_DM)
Temp_MM = MongoMapper if defined?(::MongoMapper) and not defined?(Temp_MM)
Temp_CP = CouchPotato if defined?(::CouchPotato) and not defined?(Temp_CP)
end
before(:each) do
DatabaseCleaner::ActiveRecord::Transaction.stub!(:new).and_return(@strategy = mock('strategy'))
Object.const_set('ActiveRecord', "just mocking out the constant here...") unless defined?(::ActiveRecord)
DatabaseCleaner.strategy = nil
DatabaseCleaner.orm = nil
# Remove ORM consts for these tests
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord)
Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper)
Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper)
Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato)
end
it "should raise an error when no ORM is detected" do
running { DatabaseCleaner::Base.new(:autodetect) }.should raise_error(DatabaseCleaner::NoORMDetected)
end
it "should detect ActiveRecord first" do
Object.const_set('ActiveRecord','Actively mocking records.')
Object.const_set('DataMapper', 'Mapping data mocks')
Object.const_set('MongoMapper', 'Mapping mock mongos')
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :active_record
end
it "should detect DataMapper second" do
Object.const_set('DataMapper', 'Mapping data mocks')
Object.const_set('MongoMapper', 'Mapping mock mongos')
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :data_mapper
end
it "should detect MongoMapper third" do
Object.const_set('MongoMapper', 'Mapping mock mongos')
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :mongo_mapper
end
it "should detect CouchPotato last" do
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :couch_potato
end
after(:all) do
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord)
Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper)
Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper)
Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato)
# Restore ORMs
ActiveRecord = Temp_AR if defined? Temp_AR
DataMapper = Temp_DM if defined? Temp_DM
MongoMapper = Temp_MM if defined? Temp_MM
CouchPotato = Temp_CP if defined? Temp_CP
end
end
end
context "single orm" do
let (:connection) { ::DatabaseCleaner.connections.first }
it "should proxy strategy=" do
stratagum = mock("stratagum")
connection.should_receive(:strategy=).with(stratagum)
::DatabaseCleaner.strategy = stratagum
end
it "should proxy orm=" do
orm = mock("orm")
connection.should_receive(:orm=).with(orm)
::DatabaseCleaner.orm = orm
end
it "should proxy start" do
connection.should_receive(:start)
::DatabaseCleaner.start
end
it "should proxy clean" do
connection.should_receive(:clean)
::DatabaseCleaner.clean
end
it "should proxy clean_with" do
stratagem = mock("stratgem")
connection.should_receive(:clean_with).with(stratagem)
::DatabaseCleaner.clean_with stratagem
end
end
describe ::DatabaseCleaner::Base do
describe "orm_module" do
it "should proxy to the class method"
end
let(:strategy) { mock("stratagum") }
context "active record" do
let(:cleaner) { ::DatabaseCleaner::Base.new(:active_record) }
before(:each) do
::DatabaseCleaner::ActiveRecord::Transaction.stub!(:new).and_return(strategy)
#Object.const_set('ActiveRecord', "just mocking out the constant here...") unless defined?(::ActiveRecord)
cleaner.strategy = nil
end
describe ".create_strategy" do
it "should initialize and return the appropirate strategy" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash')
result = DatabaseCleaner.create_strategy(:transaction, {'options' => 'hash'})
result.should == @strategy
result = cleaner.create_strategy(:transaction, {'options' => 'hash'})
result.should == strategy
end
end
describe ".clean_with" do
it "should initialize the appropirate strategy and clean with it" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash')
@strategy.should_receive(:clean)
DatabaseCleaner.clean_with(:transaction, 'options' => 'hash')
strategy.should_receive(:clean)
cleaner.clean_with(:transaction, 'options' => 'hash')
end
end
describe ".strategy=" do
it "should initialize the appropirate strategy based on the ORM adapter detected" do
it "should initialize the appropirate strategy for active record" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash')
DatabaseCleaner.strategy = :transaction, {'options' => 'hash'}
Object.send(:remove_const, 'ActiveRecord')
Object.const_set('DataMapper', "just mocking out the constant here...")
DatabaseCleaner.orm = nil
DatabaseCleaner::DataMapper::Transaction.should_receive(:new).with(no_args)
DatabaseCleaner.strategy = :transaction
end
it "should raise an error when no ORM is detected" do
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord)
Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper)
Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato)
running { DatabaseCleaner.strategy = :transaction }.should raise_error(DatabaseCleaner::NoORMDetected)
end
it "should use the strategy version of the ORM specified with #orm=" do
DatabaseCleaner.orm = 'data_mapper'
DatabaseCleaner::DataMapper::Transaction.should_receive(:new)
DatabaseCleaner.strategy = :transaction
end
it "should raise an error when multiple args is passed in and the first is not a symbol" do
running { DatabaseCleaner.strategy=Object.new, {:foo => 'bar'} }.should raise_error(ArgumentError)
end
it "should raise an error when the specified strategy is not found" do
running { DatabaseCleaner.strategy = :foo }.should raise_error(DatabaseCleaner::UnknownStrategySpecified)
cleaner.strategy = :transaction, {'options' => 'hash'}
end
it "should allow any object to be set as the strategy" do
@ -96,23 +210,108 @@ describe DatabaseCleaner do
running { DatabaseCleaner.strategy = mock_strategy }.should_not raise_error
end
it "should raise an error when the specified strategy is not found" do
running { DatabaseCleaner.strategy = :foo }.should raise_error(DatabaseCleaner::UnknownStrategySpecified)
end
it "should raise an error when multiple args is passed in and the first is not a symbol" do
running { DatabaseCleaner.strategy=Object.new, {:foo => 'bar'} }.should raise_error(ArgumentError)
end
end
%w[start clean].each do |strategy_method|
describe ".#{strategy_method}" do
it "should be delgated to the strategy set with strategy=" do
DatabaseCleaner.strategy = :transaction
cleaner.strategy = :transaction
@strategy.should_receive(strategy_method)
strategy.should_receive(strategy_method)
DatabaseCleaner.send(strategy_method)
cleaner.send(strategy_method)
end
it "should raise en error when no strategy has been set" do
running { DatabaseCleaner.send(strategy_method) }.should raise_error(DatabaseCleaner::NoStrategySetError)
running { cleaner.send(strategy_method) }.should raise_error(DatabaseCleaner::NoStrategySetError)
end
end
end
end
context "data mapper" do
let(:cleaner) { ::DatabaseCleaner::Base.new(:data_mapper) }
before(:each) do
::DatabaseCleaner::DataMapper::Transaction.stub!(:new).and_return(strategy)
#Object.const_set('ActiveRecord', "just mocking out the constant here...") unless defined?(::ActiveRecord)
cleaner.strategy = nil
end
describe ".create_strategy" do
it "should initialize and return the appropirate strategy" do
DatabaseCleaner::DataMapper::Transaction.should_receive(:new)
result = cleaner.create_strategy(:transaction)
result.should == strategy
end
end
describe ".clean_with" do
it "should initialize the appropirate strategy and clean with it" do
DatabaseCleaner::DataMapper::Transaction.should_receive(:new)
strategy.should_receive(:clean)
cleaner.clean_with(:transaction)
end
end
describe ".strategy=" do
it "should initalize the appropriate strategy for data mapper" do
DatabaseCleaner::DataMapper::Transaction.should_receive(:new).with(no_args)
cleaner.strategy = :transaction
end
it "should allow any object to be set as the strategy" do
mock_strategy = mock('strategy')
running { cleaner.strategy = mock_strategy }.should_not raise_error
end
it "should raise an error when the specified strategy is not found" do
running { cleaner.strategy = :foo }.should raise_error(DatabaseCleaner::UnknownStrategySpecified)
end
it "should raise an error when multiple args is passed in and the first is not a symbol" do
running { cleaner.strategy=Object.new, {:foo => 'bar'} }.should raise_error(ArgumentError)
end
end
%w[start clean].each do |strategy_method|
describe ".#{strategy_method}" do
it "should be delgated to the strategy set with strategy=" do
cleaner.strategy = :transaction
strategy.should_receive(strategy_method)
cleaner.send(strategy_method)
end
it "should raise en error when no strategy has been set" do
running { cleaner.send(strategy_method) }.should raise_error(DatabaseCleaner::NoStrategySetError)
end
end
end
end
# it "should raise an error when no ORM is detected" do
# Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord)
# Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper)
# Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato)
#
# running { DatabaseCleaner.strategy = :transaction }.should raise_error(DatabaseCleaner::NoORMDetected)
# end
# it "should use the strategy version of the ORM specified with #orm=" do
# DatabaseCleaner.orm = 'data_mapper'
# DatabaseCleaner::DataMapper::Transaction.should_receive(:new)
#
# DatabaseCleaner.strategy = :transaction
# end
end
end

View file

@ -4,3 +4,4 @@
mtime
--reverse
--backtrace
--debugger