5

私はShoulda + FactoryGirlテストをスピードアップする方法を探しています。

テストしようとしているモデル(StudentExam)には、他のモデルとの関連付けがあります。これらの関連オブジェクトは、を作成する前に存在している必要がありますStudentExam。そのため、で作成されsetupます。

ただし、モデルの1つ(School)の作成にはかなりの時間がかかります。setupすべてのステートメントの前に呼び出されるためshould、テストケース全体の実行には何年もかかります。つまり、実行されるすべてのshouldステートメントに対して新しい、、が作成されます@school@student@topic@exam

これらのオブジェクトを一度だけ作成する方法を探しています。テストケースの残りの部分を通して持続するレコードを作成できるstartupforメソッドのようなものはありますか?before_all

基本的に私はRSpecのbefore(:all)とまったく同じものを探しています。これらのテストではこれらの高価なオブジェクトが変更されることはないため、依存関係の問題については心配していません。

これがテストケースの例です。長いコードについてお詫びします(私も要点を作成しました):

# 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
4

4 に答える 4

2

問題がこれらのレコードを1回だけ作成することである場合は、クラス変数を使用できます。これはクリーンなアプローチではありませんが、少なくとも機能するはずです。

# 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
于 2009-11-03T23:19:00.750 に答える
2

どんなテストを書こうとしていますか?これらすべてのオブジェクトが適切に調整されていることを実際に確認したい場合は、統合テストを作成しているので、速度は主な関心事ではありません。ただし、モデルを単体テストしようとしている場合は、積極的にスタブすることで、より良い結果を得ることができます。

たとえば、exam.location(または呼び出しているもの)を呼び出すときに、試験で学校協会の名前が使用されていることを確認しようとしている場合は、学校全体のオブジェクトは必要ありません。試験が学校で正しいメソッドを呼び出していることを確認する必要があります。それをテストするには、次のようなことを行うことができます(Test :: UnitとMochaを使用するのは、私がよく知っていることだからです)。

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

基本的に、オブジェクトの構築にはコストがかかりすぎるために単体テストを高速化する必要がある場合、実際には単体テストではありません。上記のすべてのテストケースは、単体テストレベルである必要があると感じているため、スタブスタブスタブです。

于 2009-11-04T02:39:56.500 に答える
0

http://m.onkey.org/2009/9/20/make-your-shoulda-tests-faster-with-fast_contextは、shoulda/factory-girlテストを高速化する方法についての優れた投稿です。 fast_context。それがあなたが必要とするものでないかどうか私に知らせてください。

于 2009-11-03T23:13:40.147 に答える
0

fast_contextgithub link )と呼ばれるプラグインがあり、shouldステートメントを単一のコンテキストに結合してテストを高速化します。

テストを高速化するために使用しているもう1つの方法は、フィクスチャデータを事前に入力することです。FactoryGirlは、セットアップブロックが実行されるたびにこれらのレコードを作成するため、低速です。

ActiveRecordを使用してテストデータベースに事前入力するFixieというプラグインを作成したので、テストに必要なレコードはすでに作成されています。実行時に新しいレコードを作成する場合も、FixieをFactoryGirlと一緒に使用できます。

于 2009-11-03T23:17:03.097 に答える