RSpec - 如何模拟存储过程

时间:2012-12-24 15:27:30

标签: ruby postgresql rspec mocking

考虑以下stored procedure

CREATE OR REPLACE FUNCTION get_supported_locales()
RETURNS TABLE(
  code character varying(10)
) AS
...

以下方法调用它:

def self.supported_locales
  query = "SELECT code FROM get_supported_locales();"
  res = ActiveRecord::Base.connection.execute(query)
  res.values.flatten
end

我正在尝试为这个方法编写一个测试但是在模拟时我遇到了一些问题:

it "should list an intersection of locales available on the app and on last fm" do
  res = mock(PG::Result)
  res.should_receive(:values).and_return(['en', 'pt'])
  ActiveRecord::Base.connection.stub(:execute).and_return(res)

  Language.supported_locales.should =~ ['pt', 'en']
end

此测试已成功,但在此测试之后运行的任何测试都会显示以下消息:

WARNING:  there is already a transaction in progress

为什么会这样?我在做嘲笑吗

数据库是postgres 9.1。

1 个答案:

答案 0 :(得分:2)

您的测试正在使用数据库级事务运行。测试完成后,将回滚事务,以便测试中所做的任何更改都不会实际保存到数据库中。在您的情况下,由于您已在ActiveRecord连接上删除了execute方法,因此无法进行此回滚。

您可以全局禁用事务并切换到使用DatabaseCleaner启用/禁用各种测试的事务。然后,您可以默认设置通过DatabaseCleaner使用事务,这样您的现有测试就不会改变,然后在这一个测试中选择禁用事务以支持其他策略(例如null策略,因为没有清理是做了这个测试)。

This other SO post表示您可以避免全局禁用交易并在每次测试的基础上关闭它们,我自己也没试过。