2016-08-10 16 views
0

我正在編寫使用RoR生成的PDF的規格&大蝦。這些PDF有很多過濾器選項(其中24個)。爲了不錯過任何重要的規格,我在before :context塊中生成過濾器選項並將它們保存在實例變量中。在共享示例調用中使用let循環變量

當我的問題開始時,試圖迭代所有篩選器選項並運行共享示例,以測試不同的篩選器沒有太大改變的基礎知識。

這是我的代碼看起來像所有這些過濾器和單證篩選器(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 

我有2個大問題:

一個是,這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。這個問題看起來很相似,但可惜的是,在它周圍的區塊沒有做太多的工作。

24.times do |t| 
    describe 
    # same as before 
    end 
end 

有趣的是,雖然,在設置的老毛病又犯puts t時,這將是6每一次,它給我留下了一點困惑。

我還應該提一下,將它們分開的原因是我已經共享了僅適用於某些過濾器的示例。如果有人有更好的想法,例如迭代@major_filter_options,然後根據當前散列號key調用特定的共享示例,那麼我就是耳朵!

+0

我不能肯定地說,但'include_examples'每個上下文只有一次的作品。我認爲你必須用一個uniq環境來包圍它,比如'context「...#{t}」do' – slowjack2k

回答

2

關於你不能打電話給.times您在before :context塊定義的實例變量:

RSpec的工程分兩期進行。在第一階段,它在spec文件中執行Ruby代碼; letbeforeit方法存儲它們的塊以便稍後運行。在第二階段,它實際上運行測試,即letbeforeit塊的內容。在第二階段之前,before :context塊沒有定義thost實例變量,所以在第一階段運行的.times語句不能查看實例變量。

解決方案是將過濾器選項放置在RSpec到達.times語句之前初始化的位置,就像常量一樣。

關於在一個循環中include_examples始終使用循環變量的值相同:

include_examples包括在當前上下文中的給定的共享的例子。如果多次包含相同的示例,這些示例本身將包含多次,但最後一個包含中的let將覆蓋以前所有內容中的letsThe RSpec documentation has a clear example.

解決方案是使用it_behaves_like而不是include_examplesit_behaves_like將包含的示例放入嵌套示例組中,因此let s不能相互覆蓋。

應用這些兩種解決方案提供了類似以下內容:

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 
+0

這是非常有幫助的,謝謝! – sLeitner

+0

你能想到爲什麼這些循環會單獨工作的任何理由(如果我註釋掉其他),但不能組合使用?我的意思是測試通過。但是運行一切會導致一些失敗的測試,並且調整哈希以省略一些過濾器選項會導致不同的測試失敗。 我把最小的必需示例(重現失敗)降低到50%(仍然〜350),並且對它們運行rspec --bisect,但是好像它需要很長時間,一個多小時後我看到這個' - 剩下的沒有失敗的例子(337):' – sLeitner

+0

我在問題中沒有看到,我沒有在我的答案中提出任何應該有副作用,可能會打破以後的測試。除非你能想到這些測試會改變全局狀態,否則'rspec --bisect'和調試結果看起來就像是要走的路。 –