Ruby on rails 使用RSpec测试依赖外部Cassandra调用的方法

Ruby on rails 使用RSpec测试依赖外部Cassandra调用的方法,ruby-on-rails,ruby,rspec,cassandra,Ruby On Rails,Ruby,Rspec,Cassandra,我正试图提高ActiveRecord模型的测试覆盖率,该模型通过查询Cassandra数据库来创建CSV文件。我们使用RSpec。我很难弄清楚如何测试下面显示的cassandra_文件方法,因为它调用cdbh(如下所示),从而创建到cassandra数据库的实时连接 我试过这样做: it 'copys from cassandra' do cdbh = Cassandra.stub(:connect) date = '2013/12/27' expect(device).to re

我正试图提高ActiveRecord模型的测试覆盖率,该模型通过查询Cassandra数据库来创建CSV文件。我们使用RSpec。我很难弄清楚如何测试下面显示的
cassandra_文件
方法,因为它调用
cdbh
(如下所示),从而创建到cassandra数据库的实时连接

我试过这样做:

it 'copys from cassandra' do
  cdbh = Cassandra.stub(:connect)
  date = '2013/12/27'

  expect(device).to receive(:save_csv).with(date, cdbh.execute(options))
  device.raw_file(Date.new(2013,12,27))
end
但我得到了这个错误:

Failures:

  1) Device raw_file generic device copys from cassandra
     Failure/Error: Unable to find matching line from backtrace
     NoMethodError:
       undefined method `stub' for Cassandra:Module
我研究了其他一些关于存根API调用的问题,但大多数建议使用的gem,如或,似乎对这个特定用例没有用处,因为我不尝试复制HTTP请求。有没有更好的方法来测试这一点?这是一个合理的测试方法,还是它比它的价值更麻烦

提前感谢您的帮助

模型方法:

def cassandra_file(date)
  if customer.name.downcase == 'customer name'
    q = 'SELECT * FROM readings WHERE device = ? and date in (?, ?, ?)'
    return save_csv(
             date,
             cdbh.execute(q, guid, (date.to_date - 1).iso8601, date.to_date.iso8601, (date.to_date + 1).iso8601))
  else
    q = 'SELECT * FROM readings WHERE device = ? and date = ?'
    return save_csv(
             date,
             cdbh.execute(q, guid, date.to_date.iso8601))
  end
end

...

def cdbh
  return unless ENV['CASSANDRA_HOSTS']
  @cdbh ||= Cassandra.connect(hosts: ENV['CASSANDRA_HOSTS'].split(/,/)).connect('hurricane')
end

在我看来,您使用stubing的方法是正确的——模型/单元测试“应该”测试消息传递(而集成/验收测试有效地覆盖了数据库交互)

然而,我认为您的方法虽然不太复杂,但尝试做的太多,这影响了您编写干净测试的能力。(对我来说,代码是“我应该把这个存根放在哪里?”并且几乎是在那里敲打它!)

一个简单的建议可能是提取一些方法甚至类,因为
cassandra_文件
raw_文件
?)似乎有多个输入/输出或副作用,并且有点纠结

它让人想起了SOLID fame的单一责任原则(尽管有人说这可以用Ruby描述)。我看到了条件查询生成、数据库(外部系统)调用和文件输出。虽然这是一个相对较短的方法,但仍然有很多事情要做

目前有一个学派的模型没有处理这些问题——它们都是poro,“外包”到/lib或其他地方,而让ActiveRecord模型成为模型。(因此瘦控制器/胖模型被认为是第一步,这可能是下一步。)

如果你有时间和兴趣,我建议你花更多的时间研究这个话题,因为有很多文章以及Ruby会议上讨论这个话题的有趣演示。(目前我真的在从中挖掘任何东西。)


如果不是的话,我想说你很接近了,也许只需要按照建议提取一些方法,并简化模型,使自己的测试更容易。

感谢您的全面回复。我的目标是重构这段代码,并按照您所说的去做,并将所有的比特提取到单独的方法中。然而,我希望得到保证,我没有回归功能,因此我希望在尝试分解其他人的代码之前,用测试覆盖当前代码。有什么建议吗?一种想法是,如果在重构之前需要保证,可以编写一个“哑”测试,只验证函数的正常输出,而不引入存根查询的复杂性。(换句话说,如果它要改变,为什么还要花更多的时间在它上面呢?)如果只是暂时的,稍微放慢测试套件的速度就没那么重要了。只是一个想法。。。