Ruby on rails rspec测试比rails控制台慢得多
我花了一整天的时间试图弄明白为什么我的rspec rails测试套件需要很长时间才能完成(并非总是这样),我使用--profile来确定哪些测试需要很长时间,而且似乎每个测试访问数据库都需要30秒的时间 以下面的示例行为例:Ruby on rails rspec测试比rails控制台慢得多,ruby-on-rails,ruby,rspec,factory-bot,Ruby On Rails,Ruby,Rspec,Factory Bot,我花了一整天的时间试图弄明白为什么我的rspec rails测试套件需要很长时间才能完成(并非总是这样),我使用--profile来确定哪些测试需要很长时间,而且似乎每个测试访问数据库都需要30秒的时间 以下面的示例行为例: MyModel.create(args) 如果我在rails控制台中运行这一行,它会立即完成,但是如果我将它包括在rspec测试中,它会使该测试的完成时间增加30秒。另外,这一行只是一个例子,如果我在执行rails c时使用Factory girl或使用创建关系,请注意,
MyModel.create(args)
如果我在rails控制台中运行这一行,它会立即完成,但是如果我将它包括在rspec测试中,它会使该测试的完成时间增加30秒。另外,这一行只是一个例子,如果我在执行
rails c
时使用Factory girl或使用创建关系,请注意,加载需要一些时间,因为它正在启动数据库并加载将“立即”可用的rails类
每个测试规范每次都会重新创建一个干净的DB slate,因此它应该比在控制台中运行相同的命令花费更多的时间(因为DB已经设置好了)。您可以通过在(:all)之前正确地使用
,并设置测试,以尽可能多地使用同一实例,而无需重新记录,从而减轻此问题。但要延长30秒吗?我能做些什么来减少这里的开销吗?30秒似乎太多了,但这完全取决于你的测试是如何构造的(例如,它们可能会多次清除数据库)。我为我的一个简单模型添加了一个测试文件,结构告诉你什么?30秒是一次性税还是每个规格30秒?您的种子或数据库设置挂钩中是否有需要花费很长时间的内容?每次db调用需要30秒。因此,如果我在同一个规范中创建了4个模型实例,那么运行该特定规范将需要2分钟。在下一个规范中清洗并重复(我将用注释编辑上述规范)FactoryGirl工厂是否默认定义了所有不动产?可能是后面有很多疑问。您是否尝试从Rails控制台运行FactoryGirl.create(:course)?别忘了rails c-s
.p.s。我也遇到了FactoryGirl工厂运行缓慢的问题,这是由许多工厂(也称为图片工厂)造成的,这些工厂每次都上传并裁剪一张图片(占用了大部分时间)。我在控制台(rails c-s)中运行FactoryGirl.create(:course)和FactoryGirl.create(:course\u assignment)他们两人都在不到一秒钟的时间内跑掉了。如果我在我的规范中使用相同的行,它们每个都需要30秒以上。
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
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
# 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