Rails控制器测试:隔离或集成测试?

时间:2017-11-14 21:46:17

标签: ruby-on-rails unit-testing testing rspec mocking

在测试Rails控制器时,我是否有点困惑,无论是单独测试它们(模拟,更少DB命中:更快),还是以集成方式(没有模拟,很多数据库命中:更慢)。 / p>

假设我们有这个例子:

B1341209-7F09-4ECD-AE5F-3EE40D921870

单独进行测试并不会使DB更快,但是如果在产品型号中则会更快 我们添加了一个必需的描述字段,我们忘记将其添加到product_params方法中,这将是 导致产品记录未收到说明,保存时无效。

然后第一次测试将毫无问题地通过,误报我们的控制器代码是正常的,实际上在哪里 这不是因为我们必须改变product_params方法才能工作

第二次测试将失败,因为我们没有模拟创建产品。

我认为这是一个悬而未决的问题/主题,所以我想知道在进行控制器测试时是否有最佳实践。

编辑(推广这个想法)

我认为这可以概括,因为它不仅限于控制器,而是单独测试的概念,基本思路如下:

假设我们有一个函数func(x,y),这个函数有自己的单元测试。然后当我们有另一个servive(S)调用func时,我们将在其他地方测试时调用func调用,以便节省执行func的时间(特别是当它消耗时间时,比如DB命中!)

期望(func)。接收(some_x,some_y).and_return(some_value)

这是单独测试的基本思路。

这个问题,如果func的方法签名没有改变,但是现在从S传递给func的参数会使func抛出一些异常,因为func本身有一些实现变化,其中S是仍然使用旧的参数值调用func,这将导致异常。由于我们模拟了对func的调用,因此S测试不会捕获此错误,代码将成功部署。

我相信这是一般模式

3 个答案:

答案 0 :(得分:1)

我会选择集成模式。

模拟仅对长时间运行有用。你不需要模仿一切。

只要您使用事务数据库清理程序,数据库对象的创建就不会花费很长时间。

如果您的ActiveRecord对象正在执行其他一些长操作,例如调用其他第三方服务,则可以模拟这个长时间运行的操作。

如果您仍然认为隔离模式更适合您的情况,则只能使用真实对象设置一个测试用例。其他测试用例可以进行模拟。在这种情况下,您提到的误报案将被涵盖。

答案 1 :(得分:1)

一般来说,单元测试和自动化测试的一个典型属性是快速的。因此,所有重量级资源都应该被嘲笑。这包括数据库。

在设计良好的系统中,数据库是另一种应该易于更改而不会影响大部分代码库的存储介质,只有连接器才能更改。因此,从这个角度来看,数据库是一个不应该与自动化测试相关的细节。

放弃数据库的另一个原因是,它依赖于数据库中可能已从测试中抽象出来的其他信息。

在Rails中,妥协是在一个独立的数据库中运行测试,希望它足够快,不会浪费很多时间。考虑到数据库为开发人员提供的灵活性,支付该价格是合理的。

在采用单元测试爆发之后,许多从业者疯狂地嘲笑并且肆无忌惮地嘲笑一切,而没有正确判断在何处指导开发人员的努力以及从这种实践获得多少收益。对于许多雄心勃勃的开发者而言,嘲弄本身就转向了技术欲望!即手段成为目标。

故事的道德是,不要过度思考,确保预期的努力能够得到回报。

答案 2 :(得分:0)

这实际上取决于您的优先事项,以及您愿意为快速测试做出的牺牲。

当您删除数据库层时,模拟数据肯定意味着更快的测试。这样做的成本是如果只有当你的控制器与你的数据持久层交互时才会出现错误,你就不会发现错误。快速单元测试与慢速全堆栈 - 多件工作 - 在 - 时间测试一起工作。

意见因此而异。 rails测试的总体趋势似乎是转向集成/功能/系统测试并放弃大多数控制器测试。这是因为现在有更多的高级CSS样式和Javascript正在发挥作用。没有正确的答案。