如何在rails的测试中使用proc和yield覆盖类? [英] How can I overriding class with proc and yield in test on rails?

查看:53
本文介绍了如何在rails的测试中使用proc和yield覆盖类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下课程(仅作为示例),

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

下面的代码用于测试,

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"未更改1. 在大约20倍的成功率中有1个.
我认为是由于修改了Background类.可能无法在测试中覆盖或无法立即执行yield yield进程,但会延迟执行.
我尝试使用"block.call"而不是yield,但是结果是相同的.
我怎样才能使测试始终成功?

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?

推荐答案

这看起来像是经典的比赛条件. Thread.new在线程产生后立即返回,而不是在工作完成时返回.

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.

您可以使用 join 方法在返回之前等待发送线程完成执行,但是从本质上讲,它将再次等效于单个线程,因为它阻塞了调用(主)线程,直到工作完成.

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

但是,在Rails中已经有一些很棒的宝石可以用来处理后台作业.查看 SideKiq 要求.

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

这篇关于如何在rails的测试中使用proc和yield覆盖类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆