在RSpec测试中嘲笑ActiveRecord关系

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

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

user = User.find(123) post = user.posts.find(456) 

我知道如何模拟User.finduser.posts部分。 user.posts mock返回Post对象的数组。 当它到达.find(456)部分时,所有内容都会在no block givenexception。

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

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

问题是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 

然后在您的测试中, User.find(123)将返回@user并且@user.posts.find(456)将返回@post 。 如果您需要@user.posts在测试中像更多的Array ,您可以创建一个mock(Array)并存根[](index)方法。

您可以查看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