2015-09-20 21 views
1

我有下面的類(例如只),我如何重寫類與proc和產量在軌道上的測試?

class Background 
    def self.add_thread(&blcok) 
    Thread.new do 
     yield 
     ActiveRecord::Base.connection.close 
    end 
    end 
end 

class Email 
    def send_email_in_other_thread 
    Background.add_thread do 
     send_email 
    end 
    end 
    def send_email 
    UserMailer.greeting_email.deliver_now 
    end 
end 

而且下面的代碼是用於測試,

class EmailTest < ActiveSupport::TestCase 
    class Background 
    def self.add_thread(&block) 
     yield 
    end 
    end 

    test 'should send email' do 
    assert_difference 'ActionMailer::Base.deliveries.size', 1 do 
     send_email_in_other_thread 
    end 
    end 
end 

但此測試失敗, 「的ActionMailer :: Base.deliveries.size」 沒」 t改爲1. 1次約20次成功。
我認爲這是因爲修改後臺類。也許在測試中重寫不起作用,或者yield proc不會立即執行,而是延遲。
我試過'block.call'而不是yield,但結果是一樣的。
我怎樣才能使這個測試總是成功?

回答

0

這看起來像一個經典的競爭條件。 Thread.new在線程產生後立即返回,而不是在工作完成時返回。

由於您的主線程不會暫停執行,大部分時間斷言在郵件發送之前運行。

您可以使用join方法來等待發送線程在返回之前完成執行,但是它基本上相當於單個線程,因爲它會阻止調用(主)線程直到工作完成。

Thread.new do 
    yield 
    ActiveRecord::Base.connection.close 
end.join 

但是,在處理Rails中的後臺作業時,已經有一些很棒的gem了。例如,請查看SideKiqResque

+0

對不起,我的模棱兩可的問題讓你誤解'Thread.new'。上面的問題不是關於'Thread.new',因爲我在Test中重寫了Background類以擺脫'Thread.new'。但我不知道這種壓倒性的做法是行不通的,或者說「流程和收益」就是問題所在。 – cancue

+1

你正在嘗試在'EmailTest'類中修補'Background',但是這實際上會創建一個新的命名空間類EmailTest :: Background。 – Drenmi

+0

現在我明白了。上述測試是否有其他解決方案? – cancue