开发者

What's a nice way to verify within a unit test that an ActiveRecord transaction is being used?

开发者 https://www.devze.com 2022-12-14 12:26 出处:网络
I have a class which performs several database operations, and I want to write a unit test which verifies that these operations are all performed within a transaction. What\'s a nice clean way to do t

I have a class which performs several database operations, and I want to write a unit test which verifies that these operations are all performed within a transaction. What's a nice clean way to do that?

Here's some sample code illustrating the class I'm testing:

class StructureUpdater
  def initialize(structure)
    @structure = structure
  end

  def update_structure
    SeAccount.transaction do
      delete_existing_statistics
      delete_existing_structure
      add_campaigns
      # ... etc
    end
  end

  private

  def delete_existing_statistics
    # ...
  end

  def delete_existing_structure
    # ...
  end

  def add_campaigns
    # .开发者_StackOverflow中文版..
  end
end


Rspec lets you assert that data has changed in the scope of a particular block.

it "should delete existing statistics" do
    lambda do
        @structure_updater.update_structure
    end.should change(SeAccount, :count).by(3)
end

...or some such depending on what your schema looks like, etc. Not sure what exactly is going on in delete_existing_statistics so modify the change clause accordingly.

EDIT: Didn't understand the question at first, my apologies. You could try asserting the following to make sure these calls occur in a given order (again, using RSpec):

EDIT: You can't assert an expectation against a transaction in a test that has expectations for calls within that transaction. The closest I could come up with off the cuff was:

describe StructureUpdater do
    before(:each) do
        @structure_updater = StructureUpdater.new(Structure.new)
    end

    it "should update the model within a Transaction" do
        SeAccount.should_receive(:transaction)
        @structure_updater.update_structure
    end

    it "should do these other things" do
        @structure_updater.should_receive(:delete_existing_statistics).ordered
        @structure_updater.should_receive(:delete_existing_structure).ordered
        @structure_updater.should_receive(:add_campaigns).ordered
        @structure_updater.update_structure
    end
end

ONE MORE TRY: Another minor hack would be to force one of the later method calls in the transaction block to raise, and assert that nothing has changed in the DB. For instance, assuming Statistic is a model, and delete_existing_statistics would change the count of Statistic in the DB, you could know that call occurred in a transaction if an exception thrown later in the transaction rolled back that change. Something like:

it "should happen in a transaction" do 
    @structure_updater.stub!(:add_campaigns).and_raise
    lambda {@structure_updater.update_structure}.should_not change(Statistic, :count) 
end
0

精彩评论

暂无评论...
验证码 换一张
取 消