模块:RSpec::Core::Hooks
- 定义在
- lib/rspec/core/hooks.rb
概述
提供 before
、after
和 around
钩子,作为支持常见设置和拆卸的一种手段。此模块扩展到 ExampleGroup,使方法在任何 describe
或 context
块中可用,并在 Configuration 中包含,使它们在配置对象上可用,以定义全局设置或拆卸逻辑。
实例方法摘要 折叠
-
#after(*args, &block) ⇒ void (也称为: #prepend_after)
声明一个代码块,在每个示例后运行(使用
:example
)或在上下文中所有示例完成后运行一次(使用:context
)。 -
#append_after(*args, &block) ⇒ void
将
block
添加到同一作用域(:example
、:context
或:suite
)中after
块列表的末尾。 -
#around(*args) {|Example| ... } ⇒ void
声明一个代码块,其中一部分将在示例之前运行,而另一部分将在示例之后运行。
-
#before(*args, &block) ⇒ void (也称为: #append_before)
声明一个代码块,在每个示例之前运行(使用
:example
)或在任何示例之前运行一次(使用:context
)。 -
#prepend_before(*args, &block) ⇒ void
将
block
添加到同一作用域(:example
、:context
或:suite
)中before
块列表的开头。
实例方法细节
#after(&block) ⇒ void #after(scope, &block) ⇒ void #after(scope, *conditions, &block) ⇒ void #after(conditions, &block) ⇒ void 也称为: prepend_after
:example
和 :context
作用域也分别可用作 :each
和 :all
。请使用您喜欢的任何一个。
:suite
作用域仅支持在 RSpec.configuration
上注册的钩子,因为它们独立于任何示例或示例组。
声明一个代码块,在每个示例后运行(使用 :example
)或在上下文中所有示例完成后运行一次(使用 :context
)。有关排序的更多信息,请参阅 #before。
异常
即使 before
钩子或示例中存在异常,也保证 after
钩子会运行。当在 after
块中引发异常时,该异常会被捕获以供以后报告,并且会运行后续的 after
块。
顺序
after
钩子存储在三个作用域中,它们按顺序运行::example
、:context
和 :suite
。它们还可以声明在几个不同的位置:RSpec.configure
、父组、当前组。它们按以下顺序运行
after(:example) # Declared in the current group.
after(:example) # Declared in a parent group.
after(:example) # Declared in RSpec.configure.
after(:context) # Declared in the current group.
after(:context) # Declared in a parent group.
after(:context) # Declared in RSpec.configure.
after(:suite) # Declared in RSpec.configure.
这与 before
钩子运行的顺序相反。同样,如果在任何示例组中声明了多个 after
,它们会按声明的顺序相反运行。同样,around
钩子将在任何 after
示例钩子调用之后运行,但在任何 after
上下文钩子之前运行。
277 278 279 |
# File 'lib/rspec/core/hooks.rb', line 277 def after(*args, &block) hooks.register :prepend, :after, *args, &block end |
#append_after(*args, &block) ⇒void
将 block
添加到同一作用域(:example
、:context
或 :suite
)中 after
块列表的末尾。
有关作用域语义,请参阅 #after。
287 288 289 |
# File 'lib/rspec/core/hooks.rb', line 287 def append_after(*args, &block) hooks.register :append, :after, *args, &block end |
#around(&block) ⇒ void #around(scope, &block) ⇒ void #around(scope, *conditions, &block) ⇒ void #around(conditions, &block) ⇒ void
around
的语法类似于 before
和 after
,但语义却大不相同。before
和 after
钩子是在与它们关联的示例的上下文中运行的,而 around
钩子实际上负责运行示例。因此,around
钩子无法直接访问在示例及其关联的 before
和 after
钩子内提供的资源。
:example
/:each
是唯一支持的作用域。
声明一个代码块,其中一部分将在示例之前运行,而另一部分将在示例之后运行。您有责任运行该示例
around(:example) do |ex|
# Do some stuff before.
ex.run
# Do some stuff after.
end
产生的示例别名为 run
与 call
,这使您可以像处理 Proc
一样处理它。这在处理使用块或 proc 语法管理自身设置和拆卸的库时特别有用,例如
around(:example) {|ex| Database.transaction(&ex)}
around(:example) {|ex| FakeFS(&ex)}
顺序
around
钩子围绕示例及其钩子执行。
这意味着在任何 before
上下文钩子之后,但在任何 before
示例钩子之前,以及在任何 after
示例钩子之后,但在任何 after
上下文钩子之前。
它们不是 before
/after
的同义词。
349 350 351 |
# File 'lib/rspec/core/hooks.rb', line 349 def around(*args, &block) hooks.register :prepend, :around, *args, &block end |
#before(&block) ⇒ void #before(scope, &block) ⇒ void #before(scope, *conditions, &block) ⇒ void #before(conditions, &block) ⇒ void 也称为: append_before
:example
和 :context
作用域也分别可用作 :each
和 :all
。请使用您喜欢的任何一个。
:suite
作用域仅支持在 RSpec.configuration
上注册的钩子,因为它们独立于任何示例或示例组。
声明一个代码块,在每个示例之前运行(使用 :example
)或在任何示例之前运行一次(使用 :context
)。这些通常直接声明在它们适用的 ExampleGroup 中,但它们也可以在多个组之间共享。
您还可以使用 before(:suite)
在运行任何示例组之前运行一个代码块。这应该声明在 RSpec.configure 中。
在 before(:example)
或 before(:context)
中声明的实例变量在每个示例中都可访问。
顺序
before
钩子存储在三个作用域中,它们按顺序运行::suite
、:context
和 :example
。它们还可以声明在几个不同的位置:RSpec.configure
、父组、当前组。它们按以下顺序运行
before(:suite) # Declared in RSpec.configure.
before(:context) # Declared in RSpec.configure.
before(:context) # Declared in a parent group.
before(:context) # Declared in the current group.
before(:example) # Declared in RSpec.configure.
before(:example) # Declared in a parent group.
before(:example) # Declared in the current group.
如果在任何一个示例组中声明了多个 before
,它们会按声明的顺序运行。无论 around
钩子在何处声明,它们都将在 before
上下文钩子之后执行,但在任何 before
示例钩子之前执行。
条件
当您向 before(:example)
或 before(:context)
添加条件哈希时,RSpec 仅将该钩子应用于与条件匹配的组或示例。例如
RSpec.configure do |config|
config.before(:example, :authorized => true) do
log_in_as :authorized_user
end
end
RSpec.describe Something, :authorized => true do
# The before hook will run in before each example in this group.
end
RSpec.describe SomethingElse do
it "does something", :authorized => true do
# The before hook will run before this example.
end
it "does something else" do
# The hook will not run before this example.
end
end
请注意,过滤后的配置 :context
钩子仍然可以应用于具有匹配元数据的单个示例。就像 Ruby 的对象模型是每个对象都有一个仅有一个实例的单例类一样,RSpec 的模型是每个示例都有一个包含单个示例的单例示例组。
警告:before(:suite, :with => :conditions)
条件哈希用于与特定示例匹配。由于 before(:suite)
不是针对任何特定示例或组运行的,因此与 :suite
一起传递的条件实际上会被忽略。
异常
当在 before
块中引发异常时,RSpec 会跳过任何后续的 before
块和示例,但会运行所有 after(:example)
和 after(:context)
钩子。
警告:隐式 before
块
before
钩子也可以在共享上下文中声明,这些共享上下文要么被您隐式包含,要么被扩展库隐式包含。由于 RSpec 按每个作用域内的声明顺序运行这些钩子,因此加载顺序很重要,并且当一个 before
块依赖于在另一个 before
块中准备好的状态时,会导致混乱的结果,而该 before
块将在稍后运行。
警告:before(:context)
使用 before(:context)
来提高速度非常诱人,但我们建议您避免这样做,因为有很多问题,以及一些根本无法正常运行的东西。
上下文
before(:context)
在生成的用于提供块组上下文的示例中运行。
实例变量
在 before(:context)
中声明的实例变量在组中的所有示例之间共享。这意味着每个示例都可以更改共享对象的状态,从而导致排序依赖关系,这使得难以推理故障。
不支持的 RSpec 结构
RSpec 有几种结构会自动在每个示例之间重置状态。这些结构不打算在 before(:context)
中使用。
let
声明subject
声明- 任何模拟、存根或测试双重声明
其他框架
模拟对象框架和数据库事务管理器(如 ActiveRecord)通常围绕在示例之前进行设置,运行该示例,然后拆卸的想法而设计。这意味着模拟和存根(有时)可以在 before(:context)
中声明,但在第一个实际示例运行之前被拆卸。
您 *可以* 在 rspec-rails 的 before(:context)
中创建数据库支持的模型对象,但它不会为您包装在事务中,因此您需要自己负责在 after(:context)
块中清理。
200 201 202 |
# File 'lib/rspec/core/hooks.rb', line 200 def before(*args, &block) hooks.register :append, :before, *args, &block end |
#prepend_before(*args, &block) ⇒void
将 block
添加到同一作用域(:example
、:context
或 :suite
)中 before
块列表的前面。
有关作用域语义,请参见 #before。
210 211 212 |
# File 'lib/rspec/core/hooks.rb', line 210 def prepend_before(*args, &block) hooks.register :prepend, :before, *args, &block end |