早该+ FactoryGirl:我可以让我的测试速度更快?
-
13-09-2019 - |
题
我在寻找一种方式来加快我的早该 +的 FactoryGirl 测试。
我想测试(StudentExam
)的模型和关联到其他车型。这些关联的对象必须存在,我可以创造一个StudentExam
。出于这个原因,它们在setup
创建的。
然而,我们的模型(School
)之一需要显著的时间来创建。因为setup
得到每should
语句之前调用,整个测试情况需要亿万年来执行 - 它会创建一个新的@school
,@student
,@topic
和@exam
每一个应声明执行
我在寻找一种方式来一次创建这些对象的只有一次的。有什么样的startup
方法before_all
,让我创造这将在整个测试案例的休息吗?
基本上我寻找的东西完全一样的RSpec的之前(:所有)。我不担心,因为依赖这些测试将永远不会修改这些昂贵的对象的问题。
下面是一个例子测试用例。道歉用于长码(我还创建了一个要旨):
# A StudentExam represents an Exam taken by a Student.
# It records the start/stop time, room number, etc.
class StudentExamTest < ActiveSupport::TestCase
should_belong_to :student
should_belong_to :exam
setup do
# These objects need to be created before we can create a StudentExam. Tests will NOT modify these objects.
# @school is a very time-expensive model to create (associations, external API calls, etc).
# We need a way to create the @school *ONCE* -- there's no need to recreate it for every single test.
@school = Factory(:school)
@student = Factory(:student, :school => @school)
@topic = Factory(:topic, :school => @school)
@exam = Factory(:exam, :topic => @topic)
end
context "A StudentExam" do
setup do
@student_exam = Factory(:student_exam, :exam => @exam, :student => @student, :room_number => "WB 302")
end
should "take place at 'Some School'" do
assert_equal @student_exam, 'Some School'
end
should "be in_progress? when created" do
assert @student_exam.in_progress?
end
should "not be in_progress? when finish! is called" do
@student_exam.finish!
assert !@student_exam.in_progress
end
end
end
解决方案
如果问题是创造这些记录只有一次,你可以使用一个类变量。 这不是一个干净的做法,但至少它应该工作。
# A StudentExam represents an Exam taken by a Student.
# It records the start/stop time, room number, etc.
class StudentExamTest < ActiveSupport::TestCase
should_belong_to :student
should_belong_to :exam
# These objects need to be created before we can create a StudentExam. Tests will NOT modify these objects.
# @school is a very time-expensive model to create (associations, external API calls, etc).
# We need a way to create the @school *ONCE* -- there's no need to recreate it for every single test.
@@school = Factory(:school)
@@student = Factory(:student, :school => @@school)
@@topic = Factory(:topic, :school => @@school)
@@exam = Factory(:exam, :topic => @@topic)
context "A StudentExam" do
setup do
@student_exam = Factory(:student_exam, :exam => @@exam, :student => @@student, :room_number => "WB 302")
end
should "take place at 'Some School'" do
assert_equal @student_exam, 'Some School'
end
should "be in_progress? when created" do
assert @student_exam.in_progress?
end
should "not be in_progress? when finish! is called" do
@@student_exam.finish!
assert !@student_exam.in_progress
end
end
end
编辑:要修复超难看的解决方法推迟评估与实例方法
。# A StudentExam represents an Exam taken by a Student.
# It records the start/stop time, room number, etc.
class StudentExamTest < ActiveSupport::TestCase
...
private
def school
@@school ||= Factory(:school)
end
# use school instead of @@school
def student
@@school ||= Factory(:student, :school => school)
end
end
其他提示
什么样的测试,你想写?如果你真的想确保所有这些对象进行适当的协调,你正在写一个集成测试和速度是不是你首要关注的问题。不过,如果你想单元测试的模型,你可以通过积极磕碰达到更好的效果。
例如,如果你想检查考试使用其学校协会的名称,当你调用exam.location(或任何你要调用它),你并不需要一个全校对象。你只需要确保考试呼吁学校正确的方法。为了验证这一点,你可以不喜欢以下(使用测试::单位和摩卡因为那是我熟悉):
test "exam gets location from school name" do
school = stub_everything
school.expects(:name).returns(:a_school_name)
exam = Factory(:exam, :school => school)
assert_equal :a_school_name, exam.location
end
基本上,如果你需要加快你的单元测试,因为对象是构建太贵了,你不是真的单元测试。所有的测试案例上述感觉他们应该在单元测试电平,所以存根存根存根!
HTTP://米.onkey.org / 2009/9/20 /化妆你,早该检验更快的与 - fast_context 是如何使你早该/工厂女孩测试更快的优秀岗位,使用的宝石叫fast_context 。让我知道,如果它不是你所需要的。
有一种称为插件 fast_context ( GitHub的链接)相结合的语句应该到一个单一的背景下,加快测试
我一直在使用,以加快我的测试的另一件事是预先填充夹具数据。 FactoryGirl是缓慢的,因为它创建每个安装块运行时间的记录。
我写了一个称为 Fixie 使用ActiveRecord的预填充的测试数据库,所以插件你需要为你的测试记录已创建。如果你想创建在运行时的新记录,也可以使用Fixie与FactoryGirl一起。