我一直在花费一整天的时间来弄清楚为什么我的rspec-rails测试套件需要很长时间才能完成(这并不总是这样)我使用了--profile来确定哪些测试是花了很长时间,似乎每个测试点击数据库每次查询需要30秒。
采用以下示例行:
MyModel.create(args)
如果我在rails控制台中运行此行,它会立即完成,但如果我将其包含在rspec测试中,它会为该测试的完成时间增加30秒。此外,这一行只是一个例子,如果我使用Factory girl或使用<<创建关系同样的30秒税似乎也适用。
当然必须配置错误的东西。
见下我的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
我对rspec并不是很了解,并且我没有写出这个测试套件的很大一部分,所以也许这对某些人来说真的很明显,但我整天都在反对它。
编辑:我要添加一个模型测试:这个测试需要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
编辑2:我发现这与我的电脑有关(Mac os x 10.10.5)。当我在circle ci上运行我们的测试套件时,整个套件在不到5分钟的时间内运行。
编辑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
编辑4:刚才发现改变我的wifi网络可以解决这个问题。问题似乎与第一个无法访问mixpanel.com的网络相关的中断有关。
答案 0 :(得分:2)
执行rails c
时,请注意加载需要一些时间,因为它正在启动数据库并加载Rails类,这些类将立即可用&#34;即时#34;。
每个测试规范每次都会重新创建一个干净的DB平板,因此它应该比在控制台中运行相同的命令花费更多的时间(因为已经设置了DB)。您可以通过正确使用before(:all)
并以尽可能多地使用相同实例的方式设置测试来缓解这种情况。