http://betterspecs.org/#subject 有一些关于subject
和let
的信息。但是,我仍然不清楚它们之间的区别。此外,SO post What is the argument against using before, let and subject in RSpec tests?说最好不要使用subject
或let
。我该去哪儿呢?我很困惑。
http://betterspecs.org/#subject 有一些关于subject
和let
的信息。但是,我仍然不清楚它们之间的区别。此外,SO post What is the argument against using before, let and subject in RSpec tests?说最好不要使用subject
或let
。我该去哪儿呢?我很困惑。
4条答案
按热度按时间0s0u357o1#
摘要:RSpec的subject是一个特殊的变量,它引用被测试的对象。可以隐式地对它设置期望,这支持单行示例。在某些惯用情况下,读者可以清楚地看到它,但在其他情况下,它很难理解,应该避免。RSpec的
let
变量只是延迟示例化(memoized)变量。它们不像主题那样难以理解,但仍然会导致混乱的测试,因此应该谨慎使用。主题
工作原理
主体是被测试的对象。RSpec对主题有明确的概念。它可以或可以不被定义。如果是,RSpec可以调用它的方法,而不显式引用它。
默认情况下,如果最外面的示例组(
describe
或context
块)的第一个参数是一个类,RSpec将创建该类的示例并将其分配给主题。例如,以下过程:字符串
您可以使用
subject
自己定义主题:型
您可以在定义主题时为其给予:
型
即使您命名了主题,您仍然可以匿名引用它:
型
可以定义多个命名主题。最近定义的命名主题是匿名
subject
。无论主题如何定义,
1.它被惰性地示例化。也就是说,所描述的类的隐式示例化或传递给
subject
的块的执行不会发生,直到subject
或命名的主题在示例中被引用。如果你希望你的显式主题被立即示例化(在它的组中的一个例子运行之前),比如说subject!
而不是subject
。1.可以隐式地对它设置期望值(不需要写
subject
或命名主题的名称):型
主题的存在就是为了支持这种单行语法。
何时使用
隐式
subject
(从示例组推断)很难理解,因为is_expected
而不使用显式接收器)还是显式使用(如subject
),它都不会向读者提供有关调用期望的对象的角色或性质的信息。it
的字符串参数),因此读者关于示例目的的唯一信息是期望本身。因此,只有在上下文可能被所有读者很好地理解并且真的不需要示例描述时,使用隐式主语才有帮助。典型的情况是使用shoulda匹配器测试ActiveRecord验证:
型
显式匿名
subject
(用subject
定义,不带名称)稍微好一点,因为读者可以看到它是如何示例化的,但是命名的主题提供了一个意图揭示的名称,但是使用命名的主题而不是
let
变量的唯一原因是如果你想在某些时候使用匿名主题,我们刚刚解释了为什么匿名主题很难理解。因此,合法使用显式匿名
subject
或命名主题非常罕见。let
变量工作原理
let
变量就像命名的主题一样,除了两个区别:let
/let!
,而不是subject
/subject!
subject
,也不允许隐式地对它调用期望。何时使用
**使用
let
来减少示例之间的重复是完全合法的。**使用let
的最安全时间是当let
变量的用途从其名称中完全清楚时(这样读者就不必找到定义,这可能需要很多行才能理解每个示例),并且它在每个示例中以相同的方式使用。如果这两种情况都不正确,那么可以考虑在一个普通的旧局部变量中定义对象,或者调用示例中的工厂方法。**
let!
是有风险的,因为它不是懒惰的。**如果有人在包含let!
的示例组中添加了一个示例,但该示例不需要let!
变量,let!
变量,并想知道它是否以及如何影响这个例子let!
变量所花费的时间,该示例将比需要的速度慢因此,如果要使用
let!
,请仅在小而简单的示例组中使用,这样将来的示例作者就不太可能落入这种陷阱。单期望每示例的迷信
有一种常见的主题或
let
变量的过度使用值得单独讨论。有些人喜欢这样使用它们:型
(This是一个简单的方法示例,它返回一个我们需要两个期望值的数字,但是如果方法返回一个更复杂的值,需要许多期望值和/或有许多副作用,都需要期望值,这种风格可以有更多的示例/期望值。
人们这样做是因为他们听说每个示例应该只有一个期望(这与每个示例应该只测试一个方法调用的有效规则相混淆),或者因为他们喜欢RSpec的技巧。不要这样做,无论是匿名或命名主题还是
let
变量!这种样式有几个问题:相反,写一个简单的例子:
型
a5g8bdjr2#
Subject
和let
只是帮助您整理和加速测试的工具。rspec社区的人确实使用它们,所以我不会担心是否可以使用它们。它们的用法相似,但用途略有不同Subject
允许您声明一个测试主题,然后在随后的任意数量的测试用例中重用它。这减少了代码重复(DRYing up your code)Let
是before: each
块的替代方案,它将测试数据分配给示例变量。Let
为您提供了一些优势。首先,它缓存值而不将其分配给示例变量。第二,它是延迟计算的,这意味着直到规范调用它时才计算它。因此,let
可以帮助您加快测试速度。我也认为let
更容易阅读xvw2m8pv3#
subject
是测试对象,通常是一个示例或类。let
用于在测试中分配变量,这些变量是惰性计算的,而不是使用示例变量。在这个帖子里有一些很好的例子。https://github.com/reachlocal/rspec-style-guide/issues/6
fnx2tebb4#
实现几乎相同
Subject和let具有不同的语义,但它们具有几乎相同的实现。然而,主语可以是隐含的:
字符串
实验对象就是你要测试的东西。
定义将在测试(或测试设置等)中使用的对象
let!
将不会延迟运行,subject!
也是如此。您可以使用它们来创建记录等。即使变量不会被显式引用。型
虽然丹有上述的一些理由,但他是少数人认为使用隐含主语是一种不好的做法。(https://www.betterspecs.org/#subject)。Rails是一个充满魔力的东西,而“每个示例一个期望”的迷信有一个好处,那就是可以准确地显示失败的地方。
应该用来定义对象,而不是调用方法
Subject和let都应该是对象,通常不是方法调用。它们是惰性计算的,但也是记忆的,每个示例只运行一次。
我使用的一个异常
我个人,有时会打破上述规则,只有当这样做。
型
它利用了即使是主体也是懒惰的这一事实。