RSpec - 在spec helper中使用`let`

时间:2015-10-19 20:32:37

标签: ruby-on-rails rspec

我有一个大型模型需要时间来初始化我的RSpec测试。

我希望每个示例都可以使用它,但是如果示例需要它,则只想加载它。

这似乎是let()延迟加载的完美用法 - 只在您需要时加载它。

在任何特定的spec文件中我都可以

require "spec_helper"

feature "foo" do
  let(:big_class) { MyBigClass.new(bar) }

  ...
end

这将使big_class可用于该spec文件中的每个示例。

有没有办法让它更全局化,以便每个spec文件和示例都可以使用它?我找不到在规范助手中初始化let的好方法。

4 个答案:

答案 0 :(得分:2)

您可以简单地定义shared context并将其包含在每个示例中。关于您的具体问题,它应如下所示:

RSpec.shared_context "Global helpers" do
  let(:big_class) { MyBigClass.new(bar) }
end

RSpec.configure do |config|
  config.include_context "Global helpers"
end

但是,在所有示例中包含共享上下文并不是一个好主意,并且来自您的问题的big_class帮助器看起来确实是特定于域的。您可以通过元数据引导共享上下文包含,例如,当您只想在要素规范中包含给定的共享上下文时(默认情况下它们都设置了:type => :feature元数据),您可以这样做:

RSpec.configure do |config|
  config.include_context "Feature spec helpers", :type => :feature
end

答案 1 :(得分:1)

您可以考虑其他方法:

  • 使用模拟对象而不是真实对象。
  • 重构初始化程序并将慢速操作提取到另一种方法

模拟对象当然会带来一系列弊端;它们会变得陈旧,使测试变得更脆弱。但对于一些不是问题的测试。

重构初始化程序是我的最爱。 E.g。

MyBigObject.new(args)

变为

MyBigObject.new(args).setup

:load_data:connect_to_database_on_the_moon或其他需要很长时间的事情。你得到了照片。

显然这意味着更改您的代码,但我发现通常可以通过其他方式提供帮助,这肯定会使测试更容易。

答案 2 :(得分:0)

您不想使用let。来自文档:

  

使用let来定义memoized帮助器方法。该值将缓存   同一个示例中的多个调用但不跨越示例

您最终会多次实例化MyBigClass。我建议在spec_helper.rb(或类似)中的某处创建一个全局帮助器方法,如果已经设置了缓存值,则使用memo-ization自己返回缓存值。

同样要非常小心这一切,因为你违反了孤立测试的规则。对你正在做的事情可能没什么问题,但这只是一面红旗。

答案 3 :(得分:0)

在使用实例变量挂钩之前使用global

来自docs

RSpec.configure do |c|
  c.before(:example) {  @big_class = MyBigClass.new(bar) }
end

RSpec.describe MyExample do
  it { expect(@big_class).to eql(MyBigClass.new(bar)) } # This code will pass
end

有关详细信息,请查看此answer

中的建议