Testing with transactions

Hello!

I experienced problems with testing transactions which are supposed to
be
rolled back, but are not, because of transactional fixtures eliminating
the
inner transaction. Can this be worked around somehow without turning off
transactional fixtures? Maybe savepoints can help this?

Does anyone have any experience with savepoints to achieve nested
transaction
functionality? Both Postgres and MySQL support savepoints (didn’t check
others).

I was thinking to make a custom patch for AR to create savepoints for
inner
transactions. Can somebody help me with achieving this (esp. with
connection_adapters and wrapping this all up as a plugin perhaps).

Something in the way of:

Wrap a block in a transaction. Returns result of block.

def transaction(start_db_transaction = true)
transaction_open = false
savepoint_open = false
savepoint_name = nil
begin
if block_given?
if start_db_transaction
begin_db_transaction
transaction_open = true
else
savepoint_name = create_savepoint
savepoint_open = true
end
yield
end
rescue Exception => database_transaction_rollback
if transaction_open
transaction_open = false
rollback_db_transaction
end
if savepoint_open
savepoint_open = false
rollback_to_savepoint(savepoint_name)
end
raise
end
ensure
commit_db_transaction if transaction_open
release_savepoint(savepoint_name) if savepoint_open
end

Best regards,
Laas

You can use a database that support nested transactions.

Pg and Oracle both do, I believe.


– Tom M.

I do most of my testing with transactional fixtures, but where I need to
test a transaction itself, I create a separate test module like:

require File.dirname(FILE) + ‘/…/test_helper’

class MyTestNoTransFixturesTest < Test::Unit::TestCase
self.use_transactional_fixtures = false
fixtures :myfixture

def test01_my_test
# tests and assertions
end
end

Julian

This is very cool. Haven’t tried it yet, but I encourage you to submit
this as a patch to the core team.


– Tom M.

Hello!

Instead of rewriting some of my tests to use non-transactional fixtures,
I
thought it would be more wise to patch AR insted. So I ended up writing
a
plugin, which now is availlable from:

http://rubyforge.org/projects/arnesttransacts

This plugin uses savepoints when one transaction has already been
started and
rolls back to/commits that savepoint instead. This is implemented by
overlaying
ActiveRecord::ConnectionAdapters::DatabaseStatements.transaction
method and adding some helper methods to postgres and mysql adapters
also.

Currently only PostgreSQL is tested, though MySQL is also implemented,
as it
uses the same syntax, but I did not have time to test it with live
database.

It would be great if some Oracle, DB2 or Firebird users could implement
this
plugin for their database also.

Comments and thougths are welcome.

Best Regards,
Laas Toom