如何使用RSpec初始化模型表,以便外部进程可以看到表的内容?

时间:2012-06-25 20:45:14

标签: ruby-on-rails-3 postgresql locking rspec-rails external-process

我正在编写一个Rails系统,它通过生成多个进程来获取数据并更新单个数据库表来从外部源提取数据。我想编写RSpec测试,这些测试产生多个进程,模拟fetch / write进程以查找并发问题。

简短问题

如何在RSpec测试中初始化表,以便外部进程可以看到表的内容? (至少,我认为这是正确的问题。继续阅读详情......)

更长的形式

我的RSpec测试的一般结构是:

it 'external task should update the correct records' do
  initialize_my_model_table_with_some_records
  spawn_external_tasks_to_update_records
  # wait for spawned processes to complete
  Process.waitall.each {|pid, status| status.exitstatus.should == 0 }
  validate_results
end

但外部进程始终将模型表视为空(通过调试打印验证)。随后,尝试更新表失败。

我很确定这是因为RSpec将表保持在锁定之下,因此它可以在测试完成后进行回滚。

所以(重复一个简短的问题):如何在RSpec测试中初始化一个表,以便外部进程可以看到表的初始化内容?

编辑#2

我注意到在进入后续测试时,表处于先前(外部)进程离开它的状态。这是有道理的:RSpec只能将表回滚到它'知道'的状态,因此外部进程所做的更改将持续存在。

这表明了一个解决方案:它似乎可以使用before(:all)来显式初始化表。但这是最干净的方法吗?

环境

  • Ruby版本1.9.3(x86_64-darwin10.8.0)
  • pg(0.13.2)
  • rails(3.2.1)
  • rspec(2.9.0)
  • rspec-rails(2.9.0)

1 个答案:

答案 0 :(得分:0)

当RSpec运行测试时,它会在事务下锁定数据库,以便在测试后回滚它。因此,任何外部进程都不会看到RSpec对数据库所做的更改。相应地,在RSpec测试之后,外部进程对数据库所做的任何更改都不会回滚。

一个例外是before(:all)after(:all)块内:RSpec所做的任何更改都将对外部进程可见。

因此,OP中的示例可以像这样工作:

describe 'with external tasks' do
  before(:all)
    initialize_my_model_table_with_some_records
  end
  after(:all)
    reinitialize_my_model_table
  end

  it 'should update the correct records' do
    spawn_external_tasks_to_update_records
    # wait for spawned processes to complete
    Process.waitall.each {|pid, status| status.exitstatus.should == 0 }
    validate_results
  end
end