Rails测试::模型验证的单元测试令人惊讶地缓慢 - I18n?

时间:2014-01-11 22:28:08

标签: ruby-on-rails ruby-on-rails-3 unit-testing minitest

我在我的Rails应用程序中进行了一个简单的测试,该测试的持续时间比其他明显相似的测试要长得多。

运行test_invalid_without_name需要1到2秒的实时时间,如下所示:

VALID_PARAMS = { name: 'Client record' }

def test_invalid_without_name
  c = Client.new(VALID_PARAMS)
  c.name = nil
  refute c.valid?, 'should not be valid without a name'
end

下一个测试test_valid_with_all_params不到1/100秒:

def test_valid_with_all_params
  c = Client.new(VALID_PARAMS)
  assert c.valid?, 'should be valid with appropriate parameters'
end

在此阶段,客户端模型非常简单:

class Client < ActiveRecord::Base

  belongs_to :entity, polymorphic: true

  validates :name, presence: true

end

任何人都可以在这里发现什么是错的,或者让我知道我应该在哪里看下去试图解决这个问题?

更新1

我使用ruby-prof来分析代码,似乎很多时候花在Psych gem上。我相信这是在ActiveRecord::..#serialize中使用的,我在另一个模型中使用如下:

class Opportunity < ActiveRecord::Base
   belongs_to :client 
   serialize :details, Hash
end

但是,在此处删除对serialize的调用对客户端测试没有任何影响(我无法理解为什么会这样,这两个类是关联的,但客户端中没有实例化机会检验)。

更新2

原因是因为I18n正在使用它而被调用。我在这一点上的假设是失败的验证导致I18n转到语言环境文件以提取错误消息。我将研究I18n进行测试......

2 个答案:

答案 0 :(得分:2)

事实证明,解决这个问题的合适方法是使用ruby-prof如下。

添加到Gemfile(在development组中):

gem 'ruby-prof'

将测试代码包含在对分析器的调用中:

def test_invalid_without_name
  RubyProf.start

  cr = Client.new(VALID_PARAMS)
  cr.name = nil
  refute cr.valid?, 'should not be valid without a name'

  result = RubyProf.stop
  printer = RubyProf::CallStackPrinter.new(result)
  printer.print(File.open(File.join(Rails.root, 'profile_invalid_without_name.html'), 'w'))
end

这将在您的Rails应用程序的根目录下创建一个交互式HTML文档,该文档显示时间花费的细分。

在这种情况下,在I18n中寻找翻译的是80%以上。我将以下行添加到config/environments/test.rb以在测试中将其删除:

  I18n.backend = I18n::Backend::KeyValue.new({})

我将来可能会做出以下额外改进:

  1. 更具体地说明了I18n的存根,因此全栈验收测试可以使用真实的东西。

  2. 编写更方便的分析方法。看起来ruby-prof提供了各种其他激活它的机制,这对初次使用来说是最简单的。

答案 1 :(得分:1)

如果没有更多信息,就无法回答这个问题。

  • 当您单独运行每个测试时会发生这种情况吗?
  • 你在setup / teardown或test_helper.rb中有什么内容吗?
  • 如果您传递名称=&gt;的哈希,是否会发生这种情况? nil而不是设置它?
  • 您是否重新定义了名字设定者?
  • 你的模特有没有回调?