2015-01-02 91 views
1

我目前正在研究一個Minitest擴展,其中包含Minitest::Runnable.run with before/after_suite回調。 Minitest的工作方式是測試類從Minitest::Runnable繼承。此外,describe塊動態創建,從他們中定義的測試類繼承的類。所以動態定義類的子類方法,正確評估子類

# Minitest::Spec inherits from Minitest::Runnable 
class TestClass < Minitest::Spec 
    describe 'a describe block' do 
    it 'should say hi' do 
     # test here 
    end 
    end 
end 

生成,從TestClass中,其name"a describe block"繼承一個新的類。這將導致Minitest流水線不斷髮展,並且每個類別都會調用Mintest::Runnable.run(例如,在每種情況下,self都會變爲包括"a describe block"在內的每個類別)。供參考:

module Minitest::Runnable 
    def self.run reporter, options = {} 
    require 'rubygems'; require 'pry'; binding.pry 
    filter = options[:filter] || '/./' 
    filter = Regexp.new $1 if filter =~ /\/(.*)\// 

    filtered_methods = self.runnable_methods.find_all { |m| 
     filter === m || filter === "#{self}##{m}" 
    } 

    with_info_handler reporter do 
     filtered_methods.each do |method_name| 
     run_one_method self, method_name, reporter 
     end 
    end 
    end 
end 

我擴展的設計允許你有一個before_suite方法,它包裝MINITEST :: Runnable.run工作:

class TestClass < Minitest::Spec 
    before_suite do 
    # do something 
    end 

    describe 'a describe block' do 
    it 'should say hi' do 
     # test here 
    end 
    end 
end 

我找到了工作大多不過我正在遇到繼承問題。當我重新定義包裝器方法時,我的新單例方法的接收器即使對於子類(即使對於descibe塊)也是TestClass。這會導致我的測試無法找到。

下面是我目前實施前套件:

module Minitest::SuiteCallbacks 
    def self.extended(base) 
    base.class_eval do 
     class << self 
     def before_suite(&before_suite_proc) 
      @before_suite_proc = before_suite_proc 

      context = self 
      original_singleton_run = method(:run) 
      define_singleton_method :run do |*args, &block| 
      # `self` here winds up being `TestClass` instead of the dynamic class 
      # (e.g. self.name => "TestClass" instead of "a describe block") 

      context.setup_before_suite 
      original_singleton_run.call(*args, &block) 
      end 
     end 
     end 
    end 
    end 
end 

這抓住當前實施run和包裝它。問題是,當它從動態"a describe block"子類的上下文中調用self裏面的方法是TestClass而不是動態類時。

對於我能做些什麼來解決這個問題有什麼想法?我的目標是能夠動態地包裝繼承鏈中的任何方法,並使其適用於所有子類。

在此先感謝!

回答

1

該錯誤與方法綁定。我要麼不得不unbind方法或開闢單獨的類,並得到參考UnboundMethod通過instance_method

def before_suite 
    # ... 
    original = instance_method(:run) 
    class << self 
    define_method :run do |*args, &block| 
     # add decorated logic 
     original.bind(self).call(*args, &block) 
    end 
    end 
end 

這是我最初的猜測,但錯誤是進一步下來堆棧(我包運行方法再次與after_suite並忘記更改該實現)。如有疑問,請發表評論!