Testing RSpec 如何更好的测试 call method

tumayun · 发布于 2016年03月15日 · 最后由 seabornlee 回复于 2016年03月19日 · 1129 次阅读
967

在写测试的时候经常要会出现如下情况

expect(user).to receive(:block_user!).with(other_user)

一般情况下这样挺好的,但是当涉及到查询时就非常麻烦了,比如在 controller 测试中

user = create :user
other_user = create :user
sign_in user
expect(user).to receive(:block_user!).with(other_user)
post :create, format: :json, user_id: other_user.id
expect(response).to have_http_status :success

这样写测试肯定通过不了,虽然在 action 查询出来的 user 与 other_user 其实就是测试代码中的 user 和 other_user,但是查询出来的 object_id 与测试代码中的不同,所以会导致下面这句测试不通过!

expect(user).to receive(:block_user!).with(other_user)

So,请教有没有什么 Gem 之类的对 receive 测试进行改进,使其就算 object_id 不同,也可以测试通过? 难道这种情况只能用如下方法解决?

expect(User).to receive(:find).with(user.id).and_return(user)
expect(User).to receive(:find).with(other_user.id).and_return(other_user)

这里不讨论测试写的好不好,只说针对上述情况的 receive 测试有没有更好的解法!

共收到 11 条回复
967

请教!

121

我觉得这里没有必要去 mock block_user 方法, 直接去检查 other_user 的 block 状态不是更好么?

测试的一个原则是: 没有必要的时候, 尽量少用 mock 来测试.

967

@lyfi2003 我会在 model 中测试 block_user! method,所以这里希望能用 mock

483

#3楼 @tumayun fixtures 或者 factory_girl 是否满足?

7072

stub 一般是在单元测试中使用,用来避免依赖。

post :create, format: :json, user_id: other_user.id是一个api调用,我觉得属于集成测试了。

而这个时候,觉得已经不用在乎哪个方法调用了,而是期待有什么样的结果。

967

@yfractal 问题是 block_user! 会在其他地方用到,如果测试结果的话,就会有很多重复的测试代码

96

首先建议使用FactoryGirl,如果测试过程中在多个断言里需要重复调用FactoryGirl生成的对象,还需要配合database_cleaner这个gem,它可以方便灵活地控制FactoryGirl生成的数据在测试数据库的保存以及测试完毕的自动删除。

7072

#6楼 @tumayun any_instance呢?

2575

首先如果只论如何用 mock 解决这个问题,那也就只能 mock User.find 了。mock 就是要模拟程序行为。楼主却想 mock 一半再绕过去,思路有些奇怪。

就测试本身而言,controller 测试因为承上启下的特殊性,更适合用来测试结果而不是过程。我看楼主在上面几楼反复强调 block_user! 在其他地方已经测到了,感觉楼主并没有完全理解测试的关注点。就你的例子而言,我对 model 和 controller 测试的看法:

  1. model 更偏单元测试,需要关注边界条件。比如 user 不能 block 他自己。
  2. controller 更偏集成测试,假设每个组件都工作正常的情况下,程序整体行为是否正确。你没必要在 controller 里穷举 User#block_user! 的所有可能情况,因为单元测试已经保证了这一点。

最后,我不怎么写 controller 测试,因为大部分情况下我都用 service object 封装业务逻辑,然后对 service object 写单元测试去了。实际行为我用 request 测试去保证(API 项目)。

967

@matsuijurina 这个 FactoryGirl 并没有关系 @darkbaby123 嗯,感觉你说的有道理,虽然可能会多一些代码,但是 controller 测试确实更偏向集成测试,重结果!

5196

我也是这么测的,下层单元测试覆盖所有情况,上层测试选择一个主要path保证通过。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册