我正在编写使用RoR& amp;虾。该PDF有一堆过滤选项(其中24个)。为了不错过任何重要的规范,我在before :context
块中生成过滤器选项并将其保存在实例变量中。
我的问题出现的地方是尝试迭代所有过滤器选项并运行共享示例,以测试不同过滤器不会发生太大变化的基础知识。
这就是我的代码对所有这些过滤器和文档过滤器的看法(filter_setting
方法只是访问特定@major_filter_options
的帮助器):
describe 'pdf' do
before :context do
@major_filter_options = {}
@major_filter_options.define_them
end
describe 'basic content' do
before :context do
@filter_options_with_docu = {}
# find all the filters that have the docu option enabled
@major_filter_options.each do |key, mfo|
@filter_options_with_docu[key] = mfo if key.to_s.include? 'docu'
end
end
24.times do |t| # can't access major_filter_options.size here.. it's nil.
include_examples 'first_3_pages' do
let(:pdf) do
filter_options = filter_setting(@major_filter_options.keys[t])
ProjectReport::ReportGenerator.new.generate(project, filter_options, user).render
end
let(:page_analysis) { PDF::Inspector::Page.analyze(pdf) }
end
end
12.times do |t| # @print_options_with_docu is also nil at this point
include_examples 'documentation_content' do
let(:pdf) do
filter_options = filter_setting(@filter_options_with_docu.keys[t])
ProjectReport::ReportGenerator.new.generate(project, filter_options, user).render
end
let(:page_analysis) { PDF::Inspector::Page.analyze(pdf) }
end
end
# ...
end
我有两大问题:
其中一个是24.times
,12.times
等等(其中有一堆)正在困扰我,因为它会使维护变得更加艰难。一个新的过滤器选项会改变所有的值,找到所有值来改变它们在我看来很容易出错。
另一个问题是变量迭代在这里这样的事实:
当我在12.times do |t|
的任何一个内部时let
实际上似乎没有迭代:
let(:pdf) do
filter_options = filter_setting(@major_filter_options.keys[t])
puts t
# ...
end
puts t
每次打印11次(过滤器每次都相同)。
经过一番阅读后,我找到了a gist example。这个问题看起来很相似,但遗憾的是在它周围放了describe
块并没有多大作用。
24.times do |t|
describe
# same as before
end
end
有趣的是,当在该设置中再次执行puts t
时,每次都会为6,这让我更加困惑。
我还应该提一下,将它们拆分成这样的原因是我分享了仅适用于某些过滤器的示例。如果有人对如何更好地了解,例如迭代@major_filter_options
,然后根据当前哈希值key
调用某些共享示例,那我就是所有的耳朵!
答案 0 :(得分:3)
关于您无法在.times
块中定义的实例变量上调用before :context
:
RSpec分两个阶段进行。在第一阶段,它执行spec文件中的Ruby代码; let
和before
和it
方法存储其块以便稍后运行。在第二阶段,它实际运行测试,即let
和before
和it
块的内容。 before :context
块在第二阶段之前不定义实例变量,因此在第一阶段运行的.times
语句无法看到实例变量。
解决方案是将过滤器选项置于RSpec到达.times
语句之前初始化的位置,如常量。
关于循环中的include_examples
,总是使用相同的循环变量值:
include_examples
包含当前上下文中的给定共享示例。如果您不止一次包含相同的示例,则示例本身将被多次包含,但最后一个包含中的let
将覆盖所有先前包含中的lets
。 The RSpec documentation has a clear example.
解决方案是使用it_behaves_like
代替include_examples
。 it_behaves_like
将包含的示例放在嵌套示例组中,因此let
不能互相覆盖。
应用这两个解决方案的方法如下:
describe 'pdf' do
describe 'basic content' do
MAJOR_FILTER_OPTIONS = # code that initializes them
MAJOR_FILTER_OPTIONS.values.each do |filter_option|
it_behaves_like 'first_3_pages' do
let(:pdf) do
filter_options = filter_setting(filter_option)
ProjectReport::ReportGenerator.new.generate(project, filter_options, user).render
end
let(:page_analysis) { PDF::Inspector::Page.analyze(pdf) }
end
end
FILTER_OPTIONS_WITH_DOCU = # code that chooses them from MAJOR_FILTER_OPTIONS
FILTER_OPTIONS_WITH_DOCU.values.each do |filter_option|
it_behaves_like 'documentation_content' do
let(:pdf) do
filter_options = filter_setting(filter_option)
ProjectReport::ReportGenerator.new.generate(project, filter_options, user).render
end
let(:page_analysis) { PDF::Inspector::Page.analyze(pdf) }
end
end
end
end