Shoulda + FactoryGirl:我可以更快地进行测试吗?

Kyl*_*Fox 5 testing ruby-on-rails shoulda factory-bot

我正在寻找一种方法来加速我的Shoulda + FactoryGirl测试.

我试图测试的模型(StudentExam)与其他模型有关联.在创建之前,这些关联对象必须存在StudentExam.出于这个原因,它们是在中创建的setup.

但是,我们的一个模型(School)需要很长时间才能创建.因为setup每一个之前被调用should语句时,整个测试用例需要亿万年来执行-它创建了一个新的@school,@student,@topic@exam每一个应声明执行.

我正在寻找一种创建一次这些对象的方法.是否有类似startupfor 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
Run Code Online (Sandbox Code Playgroud)

Sim*_*tti 2

如果问题是仅创建这些记录一次,则可以使用类变量。这不是一个干净的方法,但至少应该有效。

# 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
Run Code Online (Sandbox Code Playgroud)

编辑:要修复超级丑陋的解决方法,请使用实例方法推迟评估。

# 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
Run Code Online (Sandbox Code Playgroud)