Skip to content

Nested Describe Block - transaction handling #26

Open
jgebal opened this Issue Mar 21, 2012 · 3 comments

2 participants

@jgebal
jgebal commented Mar 21, 2012

Hi Ray!
I have an issue. I think it it more of an issue or RSpec.configure.
The thing is that the current transactions and savepoints handling doesn't work well with nested "describe" blocks.
I find using nested describe very useful.
Here is a test to show the issue.
Pleas let me know if there is a workaround for that.

require File.dirname(FILE) + '/../spec_helper'

begin
plsql.execute("DROP TABLE t_tmp_transaction_test")
rescue
end
plsql.execute("CREATE TABLE t_tmp_transaction_test (block_name VARCHAR2(100))")

def mark_transaction(bn)
plsql.t_tmp_transaction_test.insert(:block_name=>bn.last)
end

describe "Spec - Transaction Handling. Main Block" do

transaction_points = []

before(:all) do
mark_transaction(transaction_points << "Before All - Main block")
puts transaction_points.last
end

before(:each) do
mark_transaction(transaction_points << " Before Each - Main block")
puts transaction_points.last
end

[:first, :second].each do |block_no|
describe "Nested describe block - #{block_no.to_s}." do

  before(:all) do
    mark_transaction( transaction_points  << "  Before All - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  before(:each) do
    mark_transaction( transaction_points  << "   Before Each - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  [:First, :Second].each do |test_no|
    it "#{test_no.to_s} Test" do
      mark_transaction( transaction_points  << "    Running #{test_no.to_s} Unit Test - #{block_no.to_s} block" )
      puts transaction_points.last
      result = plsql.t_tmp_transaction_test.all.map{|row| row.values}.flatten
      result.should =~ transaction_points
      transaction_points.pop
    end
  end

  after(:each) do
    puts "   After Each - #{block_no.to_s} block"
    transaction_points.pop
  end

  after(:all) do
    puts "  After All - #{block_no.to_s} block"
    transaction_points.pop
  end
end

end

[:third].each do |block_no|
describe "Nested describe block - #{block_no.to_s}." do

  before(:all) do
    mark_transaction( transaction_points  << "  Before All - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  before(:each) do
    mark_transaction( transaction_points  << "   Before Each - #{block_no.to_s} block" )
    puts transaction_points.last
  end

  [:First, :Second].each do |test_no|
    it "#{test_no.to_s} Test" do
      mark_transaction( transaction_points  << "    Running #{test_no.to_s} Unit Test - #{block_no.to_s} block" )
      puts transaction_points.last
      result = plsql.t_tmp_transaction_test.all.map{|row| row.values}.flatten
      result.should =~ transaction_points
      transaction_points.pop
    end
  end

  after(:each) do
    puts "   After Each - #{block_no.to_s} block"
    transaction_points.pop
  end

  after(:all) do
    puts "  After All - #{block_no.to_s} block"
    transaction_points.pop
  end

end

end

it "Test outside the nested block" do
result = plsql.t_tmp_transaction_test.all.map{|row| row.values}.flatten
result.should =~ transaction_points
end

after(:each) do
puts " After Each - Main block"
transaction_points.pop
end

after(:all) do
puts "After All - Main block"
transaction_points.pop
end

end

@rsim
Owner
rsim commented Mar 21, 2012

Are you referring to default spec_helper.rb from ruby-plsql-spec? https://github.com/rsim/ruby-plsql-spec/blob/master/lib/plsql/spec/templates/spec_helper.rb

If you have nested describes then you probably need to implement generation of unique savepoint names for nested describes. Maybe something like this could work (haven't tested it :)):

RSpec.configure do |config|
  config.before(:all) do
    # @describe_level will start from 0 and then increment for each nested describe block
    @describe_level = (@describe_leve l| - 1) + 1
    if @describe_level > 0
      database_connections.each do |name|
        plsql(name).savepoint "before_all_#{@describe_level}"
      end
    end
  end
  config.before(:each) do
    database_connections.each do |name|
      plsql(name).savepoint "before_each"
    end
  end
  config.after(:each) do
    # Always perform rollback to savepoint after each test
    database_connections.each do |name|
      plsql(name).rollback_to "before_each"
    end
  end
  config.after(:all) do
    # Always perform rollback after each describe block
    if @describe_level > 0
      database_connections.each do |name|
        plsql(name).rollback_to "before_all_#{@describe_level}"
      end
    else
      database_connections.each do |name|
        plsql(name).rollback
      end
    end
    @describe_level -= 1
  end
end
@jgebal
jgebal commented Mar 21, 2012

I have tried a different, but similar approach.
Jet, as you run the test and look at the results, you'll see that the injected (from configure) BEFORE and AFTER blocks execute only once.
Replace the RSpec.configure with this block and run the test to see what i have in mind.
I think that the BEFORE and AFTER injected by configure should be executed each time the block is called in SPEC file, but it is not, therefore it is impossible to manage DB transaction in nested describe blocks.
Should i report it to the RSpec team, or is there a switch that you know of which enables the expected behavior.

describe_level=nil
RSpec.configure do |config|
  config.before(:suite) do
    puts "******************* conf - before siute"
    describe_level=0
  end

  config.before(:all) do
    puts "******************* conf - before all"
    describe_level+=1
    database_connections.each do |name|
      plsql(name).savepoint "before_all#{describe_level}"
    end
  end
  config.before(:each) do
    puts "******************* conf - before each"
    database_connections.each do |name|
      plsql(name).savepoint "before_each"
    end
  end
  config.after(:each) do
    puts "******************* conf - after each"
    database_connections.each do |name|
      plsql(name).rollback_to "before_each"
    end
  end
  config.after(:all) do
    puts "******************* conf - after all"
    database_connections.each do |name|
      plsql(name).rollback_to "before_all#{describe_level}"
    end
    describe_level-=1
  end
  config.after(:suite) do
    puts "******************* conf - after siute"
    database_connections.each do |name|
      plsql(name).rollback
    end
  end
end
@rsim
Owner
rsim commented Mar 21, 2012

Yes, didn't check by myself how it is actually working :)

Now checked that config.before(:all) and config.after(:all) in RSpec.configure are executed just before and after top level describe block. Probably this is intended behavior of RSpec :)

So the problem is if you do any database changes inside before(:all) block of nested describe blocks - they will not be rolled back automatically after this nested describe block. If you do not very big database changes inside before(:all) then maybe move everything to before(:each) - it will be correctly rolled back after each test. Or write tests that do not assume empty database :) At the end all changes will be rolled back after top level describe block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.