简体   繁体   English

rspec测试比Rails控制台慢得多

[英]rspec test considerably slower than rails console

I've been spending all day trying to figure out why my rspec-rails test suite takes a really long time to complete (it wasn't always this way) I've used the --profile to determine which tests are taking a long time, and it seems that every test hits the Database takes 30 seconds per query. 我整天都在努力弄清楚为什么我的rspec-rails测试套件需要很长时间才能完成(并非总是这样),我一直使用--profile来确定哪些测试需要很长时间时间,似乎每次测试命中数据库都会使每个查询花费30秒。

Take the following example line: 请看以下示例行:

MyModel.create(args)

If I run this line in the rails console it completes instantaneously, but if I include it in an rspec test, it adds 30 seconds to that test's completion time. 如果我在rails控制台中运行此行,它会立即完成,但是如果我将它包含在rspec测试中,则它将使该测试的完成时间增加30秒。 Also, this line is only an example, if I use Factory girl or create a relation using << the same 30 second tax seems to apply. 另外,如果我使用Factory girl或使用<<创建关系,则此行仅是一个示例,同样适用30秒的税收。

Surely something must be configured wrong. 当然,必须将某些配置错误。

Heres my spec_helper.rb file: 这是我的spec_helper.rb文件:

require 'simplecov'
require 'metric_fu/metrics/rcov/simplecov_formatter'
SimpleCov.formatter = SimpleCov::Formatter::MetricFu
SimpleCov.start 'rails'

# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'database_cleaner'
require 'carrierwave'

Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.use_transactional_fixtures = true
  config.infer_base_class_for_anonymous_controllers = false
  config.order = "random"
  config.mock_with :rspec
  config.include JsonSpec::Helpers
  config.include FactoryGirl::Syntax::Methods
  config.include Devise::TestHelpers, type: :controller

  # config.raise_errors_for_deprecations!
  config.infer_spec_type_from_file_location!

  config.expect_with :rspec do |c|
    c.syntax = [:should, :expect]
  end

  config.before(:suite) do
    begin
      EphemeralResponse.activate
      DatabaseCleaner.strategy = :truncation
      DatabaseCleaner.clean_with(:truncation)
      DatabaseCleaner.start
      # FactoryGirl.lint
    ensure
      DatabaseCleaner.clean
    end
  end

  config.before(:each) do
    Bullet.start_request if Bullet.enable?
  end

  config.after(:each) do
    if Bullet.enable? #&& Bullet.notification?
      # Bullet.perform_out_of_channel_notifications
      # Bullet.end_request
    end
    DatabaseCleaner.clean
  end

  config.after(:suite) do
    EphemeralResponse.deactivate
  end
end

I don't really understand a whole lot about rspec, and I didn't write a good portion of this test suite, so maybe this is really obvious to someone, but I've been beating my head against it all day. 我对rspec并不十分了解,我也没有编写此测试套件的大部分内容,因此对于某些人来说这也许确实很明显,但是我整天都在反对。

Edit: I'm going to add one of my model tests: This one takes over 5 minutes to run... 编辑:我要添加我的模型测试之一:这需要5分钟以上才能运行...

require 'spec_helper'
describe CourseAssignment do

    let(:instructor) { create(:instructor) }
    let(:student) { create(:student, id: 2) }
    let(:bundle) { create(:bundle) }
    let(:course) { create(:course) }
    let(:assignment) { create(:course_assignment, course: course) }

    it { should belong_to(:course) }
    it { should belong_to(:user) }

    describe 'CourseAssignment deletion' do
        it 'should not delete the Course or the Student' do
      instructor.courses << course # 30 seconds
      instructor.courses.last.students << student # 30 seconds
      CourseAssignment.create(course_id: course.id, user_id: student.id) # 30 seconds
      expect{CourseAssignment.last.destroy}.to change(CourseAssignment, :count).by(-1)
      expect(Student.count).to eq(1)
      expect(Course.count).to eq(1)
      expect(instructor.courses).to include(course)
        end
    end

    describe 'Student deletion' do
        it 'should delete the CourseAssignment & Student, but not the  Course' do
      instructor.courses << course # 30 seconds
      instructor.courses.last.students << student # 30 seconds
      CourseAssignment.create(course_id: course.id, user_id: student.id) # 30 seconds
      expect(student.course_assignments.count).to eq(2)

      expect{student.destroy}.to change(CourseAssignment, :count).by(-2)
      expect(Course.last.students).to be_empty
      expect(Course.count).to eq(1)
      expect(instructor.courses).to include(course)
        end
    end

    describe 'Course deletion' do
        it 'should delete the CourseAssignment' do
      instructor.courses << course # 30 seconds
      instructor.courses.last.students << student # 30 seconds
      CourseAssignment.create(course_id: course.id, user_id: student.id)

      expect{course.destroy}.to change(Course, :count).by(-1)
      expect(CourseAssignment.count).to be(0)
      instructor.reload
      expect(instructor.courses).to be_empty
        end
    end

    it 'should require a course_id' do
        no_course_id_assignment = CourseAssignment.create(course_id: '', user_id: 2) # 30 seconds
        no_course_id_assignment.should_not be_valid
    end

    it 'should require a user_id' do
        no_student_id_assignment = CourseAssignment.create(course_id: 2, user_id: '') # 30 seconds
        no_student_id_assignment.should_not be_valid
    end

end

EDIT 2: I figured out that this has something to do with my computer (Mac os x 10.10.5). 编辑2:我发现这与我的计算机(Mac os x 10.10.5)有关。 When I run our test suite on circle ci it the whole suite runs in less than 5 minutes. 当我在ci圈子上运行测试套件时,整个套件在不到5分钟的时间内运行。

Edit 3: Heres my database.yml 编辑3:这是我的database.yml

# MySQL.  Versions 4.1 and 5.0 are recommended.
#
# Install the MySQL driver:
#   gem install mysql2
#
# And be sure to use new-style password hashing:
#   http://dev.mysql.com/doc/refman/5.0/en/old-client.html
development:
  adapter: mysql2
  encoding: utf8
  database: xxxx
  username: xxxx
  password: xxxx
  host: localhost

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: mysql2
  encoding: utf8
  database: xxxx_test
  username: xxxx
  password: xxxx
  host: localhost

production:
  adapter: mysql2
  encoding: utf8
  host: localhost
  database: xxxx
  username: xxxx
  password: xxxx
  port: 3306

Edit 4: Just figured out that changing my wifi network fixes the issue. 编辑4:刚发现更改我的wifi网络可以解决此问题。 The problem seems to be related to an outage associated with the first network where mixpanel.com is unreachable. 该问题似乎与与无法访问mixpanel.com的第一个网络相关的中断有关。

When you execute rails c , note that it takes some time to load since it is starting up the DB and loading Rails classes which will be available "instantly". 执行rails c ,请注意,由于它正在启动数据库并加载“立即”可用的Rails类,因此加载会花费一些时间。

Each test spec recreates a clean DB slate each time, so it should take more time than running the same command in the console (because the DB is already set up). 每个测试规范每次都会重新创建一个干净的数据库,因此比在控制台中运行同一命令要花费更多的时间(因为该数据库已经设置)。 You can mitigate this by correctly using before(:all) and setting up tests in such a way that the the same instance is used as much as possible without needing a clean slate. 您可以通过正确地使用before(:all)并设置测试来减轻这种情况,从而尽可能多地使用同一实例而无需清理表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM