【问题标题】:Mocking ActiveRecord relationship beheavior in RSpec tests在 RSpec 测试中模拟 ActiveRecord 关系行为
【发布时间】:2010-01-29 10:15:40
【问题描述】:

我在测试时遇到了这个问题。假设我有两个模型,User 和 Post,其中 user has_many :posts。

我正在尝试指定一个包含以下内容的代码块:

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

我知道如何模拟出User.finduser.posts 部分。 user.posts 模拟返回 Post 对象数组。当它到达.find(456) 部分时,一切都会因no block given 异常而崩溃。

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

PS 在您提出停止嘲笑和使用夹具/为测试数据库播种必要数据的明显而好的答案之前,这里有一个问题:遗留方案。 User 和 Post 都在数据库视图而不是表之上工作,并且将其更改为测试数据库中的表对我来说似乎是错误的。

【问题讨论】:

    标签: ruby activerecord rspec mocking


    【解决方案1】:

    问题在于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) 方法。

    【讨论】:

    • 这是我不想做的“丑陋”方式,但是您提到的“关联代理对象”为我提供了我缺少的关键字,并且搜索它导致了我正在找,谢谢!
    • @Toms,如果您的解决方案在这些答案中是独一无二的,也许您可​​以将其添加为另一个答案。我想看看你是怎么解决的。
    • 丑陋的方式,嘲笑嘲笑。我很高兴弄清楚这一点 - 这不是我第一次遇到这种情况,这让我很困扰。
    • 我分担你的痛苦。当测试开始看起来像 OO 意大利面条时,您开始认为一定有更好的方法。
    • 如果您的测试开始变得丑陋,可能是时候重构一些代码了。我认为有用的一个常见重构(在这种特殊情况下不是)是将一系列嵌套范围包装在一个模型类方法中。
    【解决方案2】:
    猜你喜欢
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    相关资源
    最近更新 更多