为什么人们不在Rspec中访问数据库?

我经常看到在Rspec中使用mock的代码,如下所示:

describe "GET show" do it "should find and assign @question" do question = Question.new Question.should_receive(:find).with("123").and_return(question) get :show, :id => 123 assigns[:question].should == question end end 

但是为什么他们不在数据库中添加id => 123的Question ,通过get检索它并销毁它? 这是最佳做法吗? 如果我不遵守规则,会发生什么不好的事情吗?

当您编写行为测试(或unit testing)时,您尝试仅测试代码的特定部分,而不是整个堆栈。

为了更好地解释这一点,你只是表达并测试“函数A应该用这些参数调用函数B”,所以你要测试函数A而不是函数B,你为它提供了一个模拟。

这一点很重要,原因如下:

  1. 您不需要在构建代码的每台计算机上都安装数据库,如果您在公司中使用数百个项目的构建计算机(和/或持续集成),这一点非常重要。
  2. 您可以获得更好的测试结果,因为如果functionB中断,或者数据库工作不正常,则不会在functionA上出现测试失败。
  3. 您的测试运行得更快。
  4. 在每次测试之前拥有一个干净的数据库总是很痛苦。 如果先前的测试运行停止,在数据库上留下带有该ID的问题,该怎么办? 由于ID重复,您可能会遇到测试失败,而实际上function正常。
  5. 在运行测试之前,您需要正确的配置。 这不是一个令人难以置信的问题,但如果测试可以“开箱即用”运行,而不必配置数据库连接,临时测试文件的文件夹,用于测试电子邮件的SMTP服务器等等,那就更好了。

实际测试整个堆栈的测试称为“端到端测试”或“集成测试”(取决于它测试的内容)。 这些也很重要,例如,可以使用一组没有模拟数据库的测试来查看给定应用程序是否可以安全地运行与开发期间使用的DB不同的DB,并最终修复包含违规SQL语句的函数。

实际上,很多人都这样做,包括我。 一般来说,由于测试是为了检查行为,因此将数据库条目插入某些人会觉得有点不自然。

Question.new就足够了,因为它无论如何都要通过有效的rails方法,所以很多人都倾向于使用它们,因为它们更快。

但是,实际上,即使您开始使用工厂,也有时您可能会将数据插入到测试环境中。 我个人认为这没有任何问题。

总的来说,在某些情况下,测试套件非常大,不保存数据库条目是非常有利的。 但如果速度不是你最关心的问题,我会说你不必担心测试看起来如何,只要它构造得很好并且非常重要。

顺便说一下,你不需要破坏测试数据,它会在测试结束后自动完成。 因此,除非您检查实际的删除方法,否则请避免明确地执行此操作。