在RSpec测试中模仿ActiveRecord关系

Tom*_*oss 12 ruby activerecord rspec mocking

我通过测试遇到了这个问题.假设我有两个模型,User和Post,其中用户has_many:posts.

我试图指出一个包含这样的代码块:

user = User.find(123)
post = user.posts.find(456)
Run Code Online (Sandbox Code Playgroud)

我知道如何模拟User.finduser.posts部分.所述user.posts模拟返回邮对象的数组.当它分开时.find(456),一切都会no block given异常崩溃.

所以我的问题是:作为user.postsmock 的结果我会返回什么,以便该.find(456)方法可以使用它?User.first.posts.class说它是数组,但显然有更多的东西使AR风格的查找调用工作.我对于在返回的对象上模拟find方法的前景并不高兴.

PS在你提出明确而好的答案之前,先停止嘲笑和使用固定装置/使用必要的数据为测试数据库播种,这里是catch:legacy scheme.User和Post都在数据库视图之上工作而不是表,并且更改它以使它们成为测试数据库中的表似乎对我来说是错误的.

Jam*_*sen 16

问题是,user.posts是不是其实一个简单的Array; 它是一个关联代理对象.存根的方式可能是这样的(虽然确切的语法取决于你正在使用的模拟框架):

def setup
  @user = mock(User)
  User.stub(:find).with(123).return(@user)
  user_posts = mock(Object)
  @user.stub(:posts).return(user_posts)
  @post = mock(Post)
  user_posts.stub(:find).with(456).return(@post)
end
Run Code Online (Sandbox Code Playgroud)

然后在您的测试,User.find(123)将恢复@user@user.posts.find(456)返回@post.如果您需要在测试中@user.posts执行更多操作,则Array可以创建mock(Array)并存根该[](index)方法.

  • @汤姆斯,如果你的解决方案在这些答案中是独一无二的,也许你可以添加它作为另一个答案.我想看看你是如何解决它的. (7认同)
  • 我分享你的痛苦.当测试开始看起来像OO spaghetti时,你开始认为必须有更好的方法. (2认同)

rjs*_*ean 7

您可以查看RSpec提供的stub_chain方法.

http://apidock.com/rspec/Spec/Mocks/Methods/stub_chain#855-stub-chain-is-very-useful-when-testing-controller-code

更新:根据ryan2johnson9更新的文档是:https://relishapp.com/rspec/rspec-mocks/v/3-2/docs/working-with-legacy-code/message-chains