TL; DR我想知道我是否可以测试使用查询的模型方法(即find
,where
),而无需将测试对象持久保存到数据库中。
所以我是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
哪个更丑,更慢。
有什么方法可以在内存中测试这些操作吗?
我尝试手动设置children
(parent.children = [ child1, child2 ]
)
这不会导致错误,但似乎find_by
看起来不在那里,而是在DB ...
我看到a similar question在3年前出现,没有确定的答案,我想知道自那时以来是否有任何改变......
P.S。奖金问题 - 我可以对on: update
的验证做些什么?好像我必须在调用它之前至少坚持一次测试对象..
答案 0 :(得分:1)
最后一个问题。对于验证,只需断言该模型为valid?
:
parent = Parent.new
assert parent.valid?
至于他的主要问题,对此没有好的答案,人们在如何测试这些东西方面存在哲学上的差异。我的意见是,您应该测试您的业务逻辑并避免测试框架提供给您的功能(可能已经通过框架本身包含的测试验证)。
我认为你想测试Parent#default_child
(顺便说一句,不应该是default_children
?)背后的业务逻辑,它只返回Child
对象default = true
。假设您信任ActiveRecord
才能正常使用,您可以模拟(您需要添加Mocha,或使用RSpec)find_by(default: true)
之类的内容来始终返回Child
将default
属性设置为true
的对象。因为您相信ActiveRecord
会为您执行此操作。但我不会模仿每个ActiveReocrd
方法。你会浪费很多时间,最后也不会很开心。
对于某些测试,您可能会发现绝对必须拥有数据。您可以使用fixtures available in Rails,或使用FactoryGirl
之类的内容