【问题标题】:lazy evaluation and rspec's let method惰性求值和 rspec 的 let 方法
【发布时间】:2015-08-21 00:55:51
【问题描述】:

我正在阅读 The Rails 4 Way 这本书,并且正在学习 Rspec。我知道惰性求值是在使用表达式之前不求值,而急切求值是立即求值表达式。 let 使用惰性求值,在使用 let 变量之前不会执行块中的表达式。而let! 使用热切评估。

但是,我对 rspec 中的 letlet! 仍然有些困惑。让我们以书中的例子为例:

describe BlogPost do
  let(:blog_post) { BlogPost.create title: 'Hello' } 
  let!(:comment) { blog_post.comments.create text: 'first post' }

  describe "#comment" do 
    before do    
      blog_post.comment("finally got a first post") 
    end  

    it "adds the comment" do 
      expect(blog_post.comments.count).to eq(2)
    end 
  end
end

作者是这样说的:

因为注释块永远不会第一次执行 断言如果您使用 let 定义,则只有一个注释 即使实现可能正在运行,也已在此规范中添加。 通过使用 let!我们确保创建初始评论和规范 现在会过去的。

我认为使用 let 会创建两个 cmets,使用 let! 会创建三个 cmets。为什么?因为使用 let,该块将不会被执行,因此不会在那里创建 cmets。但是,注释将在 before 块中被惰性求值,所以现在我们有一个注释。然后注释块将在“添加注释”块中再次评估,因此将创建两个 cmets。既然让!立即计算,因此将创建 3 个 cmets,而不仅仅是两个。

我在这里误会了什么?

【问题讨论】:

    标签: ruby-on-rails ruby rspec


    【解决方案1】:

    您会看到没有调用惰性 comment 方法。

    但是,评论将在 before 块中进行惰性评估

    不,您向我们展示的 before 块与 let(:comment) 无关。

    使用blog_post.comment 与Rspec 或let 无关。它使用comment 方法,在您的BlogPost 模型上定义。

    然后评论块将在“添加评论”块中再次被评估

    同样,不,该块内没有任何comment 的调用。唯一更接近的是blog_post.comments,comments 复数,而不是comment,这是访问模型上的has_many 关系。

    调用let(:comment) 定义的comment 的唯一方法是使用单词comment。具有相同名称但属于不同对象的方法不相关。

    【讨论】:

    • 如果没有像上面所说的那样调用comment方法,那为什么作者说“如果你使用了一个let定义,即使实现可能在这个规范中也只会添加一个注释正在工作。通过使用 let! 我们确保创建了初始评论并且规范现在将通过(有 2 个 cmets)"
    • @Donato 因为您仍在创建评论,您只是没有通过懒惰的comment 方法创建它。 before确实创建了评论,但它与“...评论将被延迟评估”无关。在任何时候,在显示的代码中的任何地方,comment 都不会被懒惰地评估;这就是作者的观点。这就是为什么你需要let!
    • @meager 还在哪里创建评论?我只在 let 方法的块中看到创建。没有别的地方。
    • @Donato 是的,在 before 块中创建了一条评论。但这与let(:comment)无关。
    猜你喜欢
    • 2017-10-28
    • 2014-04-30
    • 2018-12-21
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 2021-12-23
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多