【问题标题】:Why do my rspec Rails tests on ONE model is taking 10 minutes ?! (Rails 3.2/rspec 2/Guard/spork)为什么我在一个模型上的 rspec Rails 测试需要 10 分钟?! (Rails 3.2/rspec 2/Guard/spork)
【发布时间】:2014-01-19 13:39:19
【问题描述】:

我在我的应用程序中定义了 rspec 测试,但它们需要很长时间! 在我的整个应用程序中,我在 37 分钟内运行了 438 个测试。每分钟只有 10 次测试。

我将 Guard 用于 rspec,Spork,所以我认为它应该更快。一定是出了什么问题。

例如,模型“Prize”的 rspec 测试需要 13 分钟才能进行 134 次测试。它非常慢!这是我的奖品规格:

require 'spec_helper'

describe Prize do
  let(:admin_user) { FactoryGirl.create(:admin_user) }

  before(:each) do
    @attr = {
      prize_name: "lorem ipsum",
      prize_short_description_for_modals: "yokoko gygy gygy",
      prize_long_description_for_rules_and_user_account:  "longer better longer better longer better",
      prize_detailed_webpage_url: "http://www.example.com",
      prize_image_url: "http://www.example2.com",
      prize_image_alt:"French",
      prize_type: "Jackpot prize",
      prize_initial_stock_quantity: 100,
      prize_remaining_stock_quantity: 5,
      prize_unit_certified_market_value:  450,
      prize_date_for_certified_market_value: 2.days.from_now,
      prize_displayed_value_on_website: 456,
      prize_require_additional_user_info: true,
      prize_max_nb_days_for_claiming: 24,
      prize_expiry_date: 75.days.from_now,
      prize_category: "computer",
      prize_sourcer_company_name: "Nefertiti",
      prize_sourcer_contact_point_name: "Gentle Man",
      prize_sourcer_contact_point_direct_phone: "01 45 67 68 77",
      prize_sourcer_contact_point_email: "gentle.man@example.com",
      prize_sourcer_how_to_contact_details: "From 9 TO 5pm, Mon. to Fri.",
      prize_sourcer_crm_profile_url: "http://www.example3com",
      prize_fully_stocked_validated:  true,
      # admin_user_id: 1,
      # as: :admin_user
    }
  end

    it { should respond_to(:prize_name) }
    it { should respond_to(:prize_short_description_for_modals) }
    it { should respond_to(:prize_long_description_for_rules_and_user_account) }
    it { should respond_to(:prize_detailed_webpage_url) }
    it { should respond_to(:prize_image_url) }
    it { should respond_to(:prize_image_alt) }
    it { should respond_to(:prize_type) }
    it { should respond_to(:prize_initial_stock_quantity) }
  it { should respond_to(:prize_remaining_stock_quantity) }
  it { should respond_to(:prize_unit_certified_market_value) }
  it { should respond_to(:prize_date_for_certified_market_value) }
  it { should respond_to(:prize_displayed_value_on_website) }
  it { should respond_to(:prize_require_additional_user_info) }
  it { should respond_to(:prize_max_nb_days_for_claiming) }
  it { should respond_to(:prize_expiry_date) }
  it { should respond_to(:prize_category) }
  it { should respond_to(:prize_sourcer_company_name) }
  it { should respond_to(:prize_sourcer_contact_point_name) }
  it { should respond_to(:prize_sourcer_contact_point_direct_phone) }
  it { should respond_to(:prize_sourcer_contact_point_email) }
  it { should respond_to(:prize_sourcer_how_to_contact_details) }
  it { should respond_to(:prize_sourcer_crm_profile_url) }
  it { should respond_to(:prize_fully_stocked_validated) }

    it { should respond_to(:admin_user_id) }
    it { should respond_to(:deal_id) }
    # its(:admin_user) { should == admin_user }

    # it { should be_valid }

  # it "should create a new instance given a valid attribute" do
  #   prize.create!(@attr)
  # end

  # -- Active Records Tests --------------------------------------------------------
  describe "tests on prize's active record" do
    it { should belong_to(:admin_user).with_foreign_key('admin_user_id')  }
    it { should belong_to(:deal) }
  end

  # Tests on Mass-Assginement
    describe "tests on prize's attributes mass assignement" do
      it { should allow_mass_assignment_of(:prize_name) }
      it { should allow_mass_assignment_of(:prize_short_description_for_modals) }
      it { should allow_mass_assignment_of(:prize_long_description_for_rules_and_user_account) }
      it { should allow_mass_assignment_of(:prize_detailed_webpage_url) }
      it { should allow_mass_assignment_of(:prize_image_url) }
      it { should allow_mass_assignment_of(:prize_image_alt) }
      it { should allow_mass_assignment_of(:prize_type) }
      it { should allow_mass_assignment_of(:prize_initial_stock_quantity) }
      it { should allow_mass_assignment_of(:prize_remaining_stock_quantity) }
      it { should allow_mass_assignment_of(:prize_unit_certified_market_value) }
      it { should allow_mass_assignment_of(:prize_date_for_certified_market_value) }
      it { should allow_mass_assignment_of(:prize_displayed_value_on_website) }
      it { should allow_mass_assignment_of(:prize_require_additional_user_info) }
      it { should allow_mass_assignment_of(:prize_max_nb_days_for_claiming) }
      it { should allow_mass_assignment_of(:prize_expiry_date) }
      it { should allow_mass_assignment_of(:prize_category) }
      it { should allow_mass_assignment_of(:prize_sourcer_company_name) }
      it { should allow_mass_assignment_of(:prize_sourcer_contact_point_name) }
      it { should allow_mass_assignment_of(:prize_sourcer_contact_point_email) }
      it { should allow_mass_assignment_of(:prize_sourcer_contact_point_direct_phone) }
      it { should allow_mass_assignment_of(:prize_sourcer_how_to_contact_details) }
      it { should allow_mass_assignment_of(:prize_sourcer_crm_profile_url) }
      it { should allow_mass_assignment_of(:prize_fully_stocked_validated) }

      it { should_not allow_mass_assignment_of(:admin_user_id) }
      it { should_not allow_mass_assignment_of(:deal_id) }

      it { should allow_mass_assignment_of(:admin_user_id).as(:admin_user) }
      it { should allow_mass_assignment_of(:deal_id).as(:admin_user) }
    end

  # -- Controller Tests --------------------------------------------------------
  describe "tests on prize's controllers" do
  end

  # -- Models Tests --------------------------------------------------------
  describe "tests on prize's models validations for prize_name" do
    it { should validate_presence_of(:prize_name) }
    it { should_not allow_value(" ").for(:prize_name) }

    it "should reject prize with names that are too long" do
      long = "a" * 101
      hash = @attr.merge(:prize_name => long)
      Prize.new(hash).should have(1).error_on(:prize_name)
    end

    it "should reject prize with names that are too short" do
      short = "a" * 4
      hash = @attr.merge(:prize_name => short)
      Prize.new(hash).should have(1).error_on(:prize_name)
    end
  end

  describe "tests on prize's models validations for prize_short_description_for_modals" do
    it { should validate_presence_of(:prize_short_description_for_modals) }
    it { should_not allow_value(" ").for(:prize_short_description_for_modals) }

    it "should reject attribute that are too long" do
      long = "a" * 301
      hash = @attr.merge(:prize_short_description_for_modals => long)
      Prize.new(hash).should have(1).error_on(:prize_short_description_for_modals)
    end

    it "should reject attribute that are too short" do
      short = "a" * 9
      hash = @attr.merge(:prize_short_description_for_modals => short)
      Prize.new(hash).should have(1).error_on(:prize_short_description_for_modals)
    end
  end

  describe "tests on prize's models validations for prize_long_description_for_rules_and_user_account" do
    it { should validate_presence_of(:prize_long_description_for_rules_and_user_account) }
    it { should_not allow_value(" ").for(:prize_long_description_for_rules_and_user_account) }

    it "should reject attribute that are too long" do
      long = "a" * 10001
      hash = @attr.merge(:prize_long_description_for_rules_and_user_account => long)
      Prize.new(hash).should have(1).error_on(:prize_long_description_for_rules_and_user_account)
    end

    it "should reject attribute that are too short" do
      short = "a" * 9
      hash = @attr.merge(:prize_long_description_for_rules_and_user_account => short)
      Prize.new(hash).should have(1).error_on(:prize_long_description_for_rules_and_user_account)
    end
  end

  describe "tests on prize's models validations for prize_detailed_webpage_url" do
    it { should validate_presence_of(:prize_detailed_webpage_url) }
    it { should_not allow_value(" ").for(:prize_detailed_webpage_url) }
    it { should_not allow_value("string but not url").for(:prize_detailed_webpage_url) }   
  end

  describe "tests on prize's models validations for prize_image_url" do
    it { should validate_presence_of(:prize_image_url) }
    it { should validate_uniqueness_of(:prize_image_url).case_insensitive }
    it { should_not allow_value(" ").for(:prize_image_url) }
    it { should_not allow_value("stringbutnoturl").for(:prize_image_url) }     
  end

  describe "tests on prize's models validations for prize_image_alt" do
    it { should validate_presence_of(:prize_image_alt) }
    it { should_not allow_value(" ").for(:prize_image_alt) }

    it "should reject attribute that are too long" do
      long = "a" * 31
      hash = @attr.merge(:prize_image_alt => long)
      Prize.new(hash).should have(1).error_on(:prize_image_alt)
    end
  end

  describe "tests on prize's models validations for prize_type" do
    it { should validate_presence_of(:prize_type) }
    it { should_not allow_value(" ").for(:prize_type) }
    it { should ensure_inclusion_of(:prize_type).in_array(PRIZE_TYPES) }
  end

  describe "tests on prize's models validations for prize_initial_stock_quantity" do
    it { should validate_presence_of(:prize_initial_stock_quantity) }
    it { should_not allow_value(" ").for(:prize_initial_stock_quantity) }

    it { should validate_numericality_of(:prize_initial_stock_quantity).only_integer }
    it { should validate_numericality_of(:prize_initial_stock_quantity).is_greater_than_or_equal_to(1) }
  end

  describe "tests on prize's models validations for prize_unit_certified_market_value" do
    it { should validate_presence_of(:prize_unit_certified_market_value) }
    it { should_not allow_value(" ").for(:prize_unit_certified_market_value) }

    it { should validate_numericality_of(:prize_unit_certified_market_value).only_integer }
    it { should validate_numericality_of(:prize_unit_certified_market_value).is_greater_than_or_equal_to(1) }
    it { should validate_numericality_of(:prize_unit_certified_market_value).is_less_than_or_equal_to(1000000) }
  end

  describe "tests on prize's models validations for prize_date_for_certified_market_value" do
    it { should validate_presence_of(:prize_date_for_certified_market_value) }
    it { should_not allow_value(Time.zone.today - 1).for(:prize_date_for_certified_market_value).on(:create) } # has to be at least today
  end

  describe "tests on prize's models validations for prize_require_additional_user_info" do
    it { should validate_presence_of(:prize_require_additional_user_info) }
    it { should ensure_inclusion_of(:prize_require_additional_user_info).in_array(%w(true false)) }
  end

  describe "tests on prize's models validations for prize_max_nb_days_for_claiming" do
    it { should validate_presence_of(:prize_max_nb_days_for_claiming) }
    it { should_not allow_value(" ").for(:prize_max_nb_days_for_claiming) }

    it { should validate_numericality_of(:prize_max_nb_days_for_claiming).only_integer }
    it { should validate_numericality_of(:prize_max_nb_days_for_claiming).is_greater_than_or_equal_to(7) }
    it { should validate_numericality_of(:prize_max_nb_days_for_claiming).is_less_than_or_equal_to(90) }
  end

  describe "tests on prize's models validations for prize_expiry_date" do
    it { should_not allow_value(Time.zone.today - 1).for(:prize_expiry_date).on(:create) } # has to be at least today
  end

  describe "tests on prize's models validations for prize_category" do
    it { should validate_presence_of(:prize_category) }
    it { should_not allow_value(" ").for(:prize_category) }
    it { should ensure_inclusion_of(:prize_category).in_array(PRIZE_CATEGORIES) }
  end

  describe "tests on prize's models validations for prize_sourcer_company_name" do

    it "should reject attribute that are too long" do
      long = "a" * 101
      hash = @attr.merge(:prize_sourcer_company_name => long)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_company_name)
    end

    it "should reject attribute that are too short" do
      short = "a" * 2
      hash = @attr.merge(:prize_sourcer_company_name => short)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_company_name)
    end
  end

  describe "tests on prize's models validations for prize_sourcer_contact_point_name" do

    it { should validate_presence_of(:prize_sourcer_contact_point_name) }
    it { should_not allow_value(" ").for(:prize_sourcer_contact_point_name)}

    it "should reject attribute that are too long" do
      long = "a" * 101
      hash = @attr.merge(:prize_sourcer_contact_point_name => long)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_name)
    end

    it "should reject attribute that are too short" do
      short = "a" * 2
      hash = @attr.merge(:prize_sourcer_contact_point_name => short)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_name)
    end
  end

  describe "tests on prize's models validations for prize_sourcer_contact_point_direct_phone" do

    context "if prize_sourcer_contact_point_name present" do # test when sourcer is present
      before { subject.stub(:prize_sourcer_company_name?) { true } }
      it { should validate_presence_of(:prize_sourcer_contact_point_direct_phone) }
      it { should_not allow_value(" ").for(:prize_sourcer_contact_point_direct_phone) }
    end 

    context "if prize_sourcer_contact_point_name not present" do # test when sourcer is not present
      before { subject.stub(:prize_sourcer_company_name?) { false } }
      it { should_not validate_presence_of(:prize_sourcer_contact_point_direct_phone) }
    end 

    it "should reject attribute that are too long" do
      long = "a" * 21
      hash = @attr.merge(:prize_sourcer_contact_point_direct_phone => long)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_direct_phone)
    end

    it "should reject attribute that are too short" do
      short = "a" * 3
      hash = @attr.merge(:prize_sourcer_contact_point_direct_phone => short)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_direct_phone)
    end
  end

  describe "tests on prize's models validations for prize_sourcer_contact_point_email" do

    context "if prize_sourcer_contact_point_name present" do # test when sourcer is present
      before { subject.stub(:prize_sourcer_company_name?) { true } }
      it { should validate_presence_of(:prize_sourcer_contact_point_email) }
      it { should_not allow_value(" ").for(:prize_sourcer_contact_point_email) }
      it { should_not allow_value("blah").for(:prize_sourcer_contact_point_email) } # need to include format with @
    end 

    context "if prize_sourcer_contact_point_name not present" do # test when sourcer is not present
      before { subject.stub(:prize_sourcer_company_name?) { false } }
      it { should_not validate_presence_of(:prize_sourcer_contact_point_email)  }
    end 

    it "should reject attribute that are too long" do
      long = "a@" * 51
      hash = @attr.merge(:prize_sourcer_contact_point_email => long)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_contact_point_email)
    end

  end

  describe "tests on prize's models validations for prize_sourcer_how_to_contact_details" do

    context "if prize_sourcer_contact_point_name present" do # test when sourcer is present
      before { subject.stub(:prize_sourcer_company_name?) { true } }
      it { should validate_presence_of(:prize_sourcer_how_to_contact_details) }
      it { should_not allow_value(" ").for(:prize_sourcer_how_to_contact_details) }
    end 

    context "if prize_sourcer_contact_point_name not present" do # test when sourcer is not present
      before { subject.stub(:prize_sourcer_company_name?) { false } }
      it { should_not validate_presence_of(:prize_sourcer_how_to_contact_details)  }
    end 

    it "should reject attribute that are too long" do
      long = "a" * 501
      hash = @attr.merge(:prize_sourcer_how_to_contact_details => long)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_how_to_contact_details)
    end

    it "should reject attribute that are too short" do
      short = "a" * 3
      hash = @attr.merge(:prize_sourcer_how_to_contact_details => short)
      Prize.new(hash).should have(1).error_on(:prize_sourcer_how_to_contact_details)
    end
  end

  describe "tests on prize's models validations for prize_sourcer_crm_profile_url" do

    context "if sourcer present" do # test when sourcer is present
      before { subject.stub(:prize_sourcer_company_name?) { true } }
      it { should validate_presence_of(:prize_sourcer_crm_profile_url) }
      it { should_not allow_value(" ").for(:prize_sourcer_crm_profile_url) }
      it { should_not allow_value("stringbuturl").for(:prize_sourcer_crm_profile_url) }
    end 

    context "if sourcer not present" do # test when sourcer is not present
      before { subject.stub(:prize_sourcer_company_name?) { false } }
      it { should_not validate_presence_of(:prize_sourcer_crm_profile_url) }
    end 
  end

  describe "tests on prize's models validations for prize_fully_stocked_validated" do
    # it { should validate_presence_of(:prize_fully_stocked_validated) }
    # it { should ensure_inclusion_of(:prize_fully_stocked_validated).in_array(%w(true false)) }
  end

  describe "tests on prize's models validations for admin_user_id" do
     it { should validate_presence_of(:admin_user_id) }
     it { should_not allow_mass_assignment_of(:admin_user_id) }
     it { should allow_mass_assignment_of(:admin_user_id).as(:admin_user) }
     it { should validate_numericality_of(:admin_user_id) }
  end  

  describe "tests on prize's models validations for deal_id" do
     it { should validate_presence_of(:deal_id) }
     it { should_not allow_mass_assignment_of(:deal_id) }
     it { should allow_mass_assignment_of(:deal_id).as(:admin_user) }
     it { should validate_numericality_of(:deal_id) }
  end 

end

我已经调整了垃圾收集器(http://makandracards.com/makandra/950-speed-up-rspec-by-deferring-garbage-collection),但几乎没有效果。

class DeferredGarbageCollection

  DEFERRED_GC_THRESHOLD = (ENV['DEFER_GC'] || 10.0).to_f

  @@last_gc_run = Time.now

  def self.start
    GC.disable if DEFERRED_GC_THRESHOLD > 0
  end

  def self.reconsider
    if DEFERRED_GC_THRESHOLD > 0 && Time.now - @@last_gc_run >= DEFERRED_GC_THRESHOLD
      GC.enable
      GC.start
      GC.disable
      @@last_gc_run = Time.now
    end
  end
end

我使用https://github.com/tmm1/perftools.rb 来评估花费的时间并了解为什么需要这么长时间。下面是perftools的分析

Total: 533 samples
      45   8.4%   8.4%       45   8.4% garbage_collector
      38   7.1%  15.6%       40   7.5% String#gsub
      35   6.6%  22.1%       35   6.6% String#=~
      20   3.8%  25.9%       20   3.8% Hash#initialize_copy
      15   2.8%  28.7%       29   5.4% Enumerable#inject
      14   2.6%  31.3%      201  37.7% I18n::Backend::Base#translate
      13   2.4%  33.8%      203  38.1% Kernel#catch
      13   2.4%  36.2%       18   3.4% URI::Parser#make_regexp
      12   2.3%  38.5%       12   2.3% PG::Connection#async_exec
      10   1.9%  40.3%      483  90.6% Array#map
       9   1.7%  42.0%       18   3.4% ActiveRecord::DynamicMatchers#respond_to?
       9   1.7%  43.7%        9   1.7% Hash#has_key?
       9   1.7%  45.4%        9   1.7% String#gsub!
       7   1.3%  46.7%        7   1.3% Class#logger
       7   1.3%  48.0%        7   1.3% Regexp#match
       6   1.1%  49.2%       12   2.3% #<Module:0x00000002cbf5a0>#normalize_key
       6   1.1%  50.3%       64  12.0% ActiveModel::Translation#human_attribute_name
       6   1.1%  51.4%        6   1.1% Kernel#is_a?
       6   1.1%  52.5%        7   1.3% Kernel.Float
       6   1.1%  53.7%        6   1.1% Regexp#===
       5   0.9%  54.6%      209  39.2% #<Module:0x00000002cbf5a0>#translate
       5   0.9%  55.5%      282  52.9% ActiveModel::Errors#generate_message
       5   0.9%  56.5%        5   0.9% Array#concat
       5   0.9%  57.4%       47   8.8% Hash#each
       5   0.9%  58.3%        5   0.9% I18n::Config#backend
       5   0.9%  59.3%       18   3.4% Kernel#dup
       5   0.9%  60.2%       10   1.9% MonitorMixin#mon_synchronize
       4   0.8%  61.0%        6   1.1% #<Module:0x00000002cbf5a0>#config
       4   0.8%  61.7%       24   4.5% #<Module:0x00000002cbf5a0>#normalize_keys
       4   0.8%  62.5%        4   0.8% ActiveRecord::Translation#lookup_ancestors
       4   0.8%  63.2%        4   0.8% Hash#delete
       4   0.8%  64.0%        6   1.1% Hash#except!
       4   0.8%  64.7%        4   0.8% Hash#values_at
       4   0.8%  65.5%       51   9.6% I18n::Backend::Simple::Implementation#lookup
       4   0.8%  66.2%        4   0.8% Kernel#require
       4   0.8%  67.0%        4   0.8% Kernel#respond_to?
       4   0.8%  67.7%        4   0.8% String#intern
       3   0.6%  68.3%        3   0.6% #<Module:0x00000002cbf5a0>#normalized_key_cache
       3   0.6%  68.9%        6   1.1% #<Module:0x007f8a0cd5fdc0>#__temp__
       3   0.6%  69.4%       10   1.9% ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#extract_pg_identifier_from_name
       3   0.6%  70.0%       42   7.9% ActiveSupport::LogSubscriber#call
       3   0.6%  70.5%        3   0.6% Array#-
       3   0.6%  71.1%        9   1.7% Hash#merge
       3   0.6%  71.7%      123  23.1% I18n::Backend::Base#default
       3   0.6%  72.2%        8   1.5% I18n::MissingTranslation::Base#initialize
       3   0.6%  72.8%        3   0.6% IO#write
       3   0.6%  73.4%        3   0.6% Kernel#throw
       3   0.6%  73.9%      480  90.1% RSpec::Core::Example#run
       3   0.6%  74.5%        3   0.6% Regexp#initialize
       3   0.6%  75.0%        3   0.6% String#%
       3   0.6%  75.6%        7   1.3% Time#minus_with_coercion
       2   0.4%  76.0%       22   4.1% ActiveModel::Validations::UrlValidator#validate_each
       2   0.4%  76.4%       20   3.8% ActiveRecord::LogSubscriber#sql
       2   0.4%  76.7%        3   0.6% ActiveSupport::LogSubscriber#color
       2   0.4%  77.1%        2   0.4% ActiveSupport::Notifications::Fanout#listeners_for
       2   0.4%  77.5%        4   0.8% Arel::Visitors::Visitor#visit
       2   0.4%  77.9%       10   1.9% Array#collect
       2   0.4%  78.2%        2   0.4% Array#flatten!
       2   0.4%  78.6%        2   0.4% Array#hash
       2   0.4%  79.0%        2   0.4% Class#configurations
       2   0.4%  79.4%        7   1.3% Class#match
       2   0.4%  79.7%       17   3.2% Hash#except
       2   0.4%  80.1%        2   0.4% Logger::SimpleFormatter#call
       2   0.4%  80.5%        2   0.4% Marshal.dump_without_mocks
       2   0.4%  80.9%       63  11.8% Module#interpolate
       2   0.4%  81.2%      361  67.7% Prize#_run__2501234485523728663__validate__1858047214644115366__callbacks
       2   0.4%  81.6%        2   0.4% Symbol#to_s
       2   0.4%  82.0%        2   0.4% Thread#[]
       2   0.4%  82.4%        2   0.4% Time#initialize
       1   0.2%  82.6%        2   0.4% #<Module:0x00000002cbf5a0>#handle_exception
       1   0.2%  82.7%        1   0.2% ActiveModel::Errors#[]
       1   0.2%  82.9%      280  52.5% ActiveModel::Errors#add
       1   0.2%  83.1%      278  52.2% ActiveModel::Errors#normalize_message
       1   0.2%  83.3%       67  12.6% ActiveModel::Name#human
       1   0.2%  83.5%      364  68.3% ActiveModel::Validations::Callbacks#run_validations!
       1   0.2%  83.7%        8   1.5% ActiveModel::Validations::NumericalityValidator#parse_raw_value_as_a_number
       1   0.2%  83.9%      149  28.0% ActiveModel::Validations::PresenceValidator#validate
       1   0.2%  84.1%        4   0.8% ActiveRecord::Associations::JoinDependency#initialize
       1   0.2%  84.2%        5   0.9% ActiveRecord::AttributeMethods#respond_to?
       1   0.2%  84.4%        1   0.2% ActiveRecord::AttributeMethods::BeforeTypeCast#read_attribute_before_type_cast
       1   0.2%  84.6%        4   0.8% ActiveRecord::AttributeMethods::Dirty#write_attribute
       1   0.2%  84.8%        1   0.2% ActiveRecord::AttributeMethods::Write#type_cast_attribute_for_write
       1   0.2%  85.0%       62  11.6% ActiveRecord::ConnectionAdapters::AbstractAdapter#log
       1   0.2%  85.2%       69  12.9% ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#disable_referential_integrity
       1   0.2%  85.4%        1   0.2% ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#quote
       1   0.2%  85.6%        1   0.2% ActiveRecord::ConnectionAdapters::PostgreSQLColumn#type_cast_with_extended_types
       1   0.2%  85.7%        1   0.2% ActiveRecord::ExplainSubscriber#call
       1   0.2%  85.9%        1   0.2% ActiveRecord::QueryMethods#where
       1   0.2%  86.1%        1   0.2% ActiveRecord::Result#hash_rows
       1   0.2%  86.3%        1   0.2% ActiveRecord::Scoping::ClassMethods#current_scope=
       1   0.2%  86.5%        5   0.9% ActiveRecord::SpawnMethods#except
       1   0.2%  86.7%       30   5.6% 

如有必要,整个文件都在这里:https://docs.google.com/document/d/16F38guxjBVFpu8Xp1rwK14TWREPcM3wtiLvfBGG7NB0/edit?usp=sharing

我阅读了几篇关于如何缩短时间的文章,但我想先了解为什么它会这么慢(30 分钟!),然后我才能选择正确的测试优化技术。

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 testing rspec


    【解决方案1】:

    似乎它大部分时间都在为您的验证生成错误消息。您可以尝试对其进行优化,但如果您正在寻找一个简单的加速,您可以只存根整个过程的一部分。我只会用"error message" 存根ActiveModel::Errors#generate_message,这样可以节省很多处理时间。

    ActiveModel::Errors.any_instance.stub(:generate_message).and_return('error message')
    

    【讨论】:

    • @Alex_Siri 谢谢,你会把它放在哪个文件中?在 spec_helper.rb 中?
    • 我会把它放在你的规范文件中的 before 块中,所以它只适用于那里
    猜你喜欢
    • 1970-01-01
    • 2012-05-27
    • 2011-12-31
    • 1970-01-01
    • 2013-10-05
    • 2016-10-05
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    相关资源
    最近更新 更多