使用ActiveRecord关联进行单元测试,而无需访问数据库

时间:2015-12-30 18:02:41

标签: ruby-on-rails ruby-on-rails-3 unit-testing activerecord

TL; DR我想知道我是否可以测试使用查询的模型方法(即findwhere,而无需将测试对象持久保存到数据库中。

所以我是rails的新手,并且正在研究现有的代码库 我注意到的一件事是我们的单元测试需要永远才能运行 经过调查,当然,罪魁祸首是我们在测试模型时将所有内容都保留在数据库中 所以,我开始尝试编写没有击中数据库的模型测试,但是我遇到了一个障碍:
当模型与其他模型关联时,对其执行的任何操作都假定所有内容都是持久的。

我们来看一个例子 -

class Parent < ActiveRecord::Base
  has_many :children, dependent: :destroy

  def default_child
    children.find_by(default: true)
  end

end

很自然地,我想测试我的default_child方法是否有效:

parent = Parent.new
default_child = parent.children.build(default: true)

assert_equal default_child, parent.default_child

但此测试失败,因为parent.default_child的实际结果为nil
这是因为在内部,default_child方法使用find_by,它似乎只适用于持久化对象的上下文。

所以我被迫写了这样的测试 -

parent = Parent.new
# I don't want to do this!!
parent.save
# why 'create' and not 'build'?
default_child = parent.children.create(default: true)

assert_equal default_child, parent.default_child

哪个更丑,更慢。
有什么方法可以在内存中测试这些操作吗?

我尝试手动设置childrenparent.children = [ child1, child2 ]) 这不会导致错误,但似乎find_by看起来不在那里,而是在DB ...

我看到a similar question在3年前出现,没有确定的答案,我想知道自那时以来是否有任何改变......

P.S。奖金问题 - 我可以对on: update的验证做些什么?好像我必须在调用它之前至少坚持一次测试对象..

1 个答案:

答案 0 :(得分:1)

最后一个问题。对于验证,只需断言该模型为valid?

parent = Parent.new
assert parent.valid?

至于他的主要问题,对此没有好的答案,人们在如何测试这些东西方面存在哲学上的差异。我的意见是,您应该测试您的业务逻辑并避免测试框架提供给您的功能(可能已经通过框架本身包含的测试验证)。

我认为你想测试Parent#default_child(顺便说一句,不应该是default_children?)背后的业务逻辑,它只返回Child对象default = true。假设您信任ActiveRecord才能正常使用,您可以模拟(您需要添加Mocha,或使用RSpecfind_by(default: true)之类的内容来始终返回Childdefault属性设置为true的对象。因为您相信ActiveRecord会为您执行此操作。但我不会模仿每个ActiveReocrd方法。你会浪费很多时间,最后也不会很开心。

对于某些测试,您可能会发现绝对必须拥有数据。您可以使用fixtures available in Rails,或使用FactoryGirl

之类的内容