How can I overriding class with proc and yield in test on rails?

空扰寡人 提交于 2019-12-11 10:15:26

问题


I have below classes(only for example),

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

And below codes are for tests,

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

But this test fails, "ActionMailer::Base.deliveries.size" didn't change by 1. And 1 in about 20 times success.
I think it is because of the modified Background class. Maybe overriding in test doesn't work or yield proc is not executed instantly but in delayed.
I tried 'block.call' instead of yield, but the result is same.
How can I make this test always be success?


回答1:


This looks like a classic race condition. Thread.new returns as soon as the thread is spawned, not when it's work is completed.

Because your main thread doesn't halt execution, most of the time your assertion is run before the mail has been sent.

You could use the join method to wait for the sending thread to finish execution before returning, but then it would essentially be equivalent to a single thread again, as it blocks the calling (main) thread until work is done.

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

There are already some great gems, however, for dealing with background jobs in Rails. Check out SideKiq and Resque for example.



来源:https://stackoverflow.com/questions/32677966/how-can-i-overriding-class-with-proc-and-yield-in-test-on-rails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!