質問

スピードを上げる方法を探しています すべきだ + 工場の女の子 テスト。

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

ただし、当社のモデルの 1 つ (School) の作成にはかなりの時間がかかります。なぜなら setup 毎回の前に呼び出されます should ステートメントを実行すると、テスト ケース全体の実行に長い時間がかかります。新しいテスト ケースが作成されます。 @school, @student, @topic そして @exam 実行されるすべての should ステートメントに対して。

これらのオブジェクトを一度に作成する方法を探しています そして一度だけ. 。のようなものはありますか? 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
役に立ちましたか?

解決

これらのレコードを 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

他のヒント

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

たとえば、example.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

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

http://m.onkey.org/2009/9/20/make-your-Shoulda-tests-faster-with-fast_context は、fast_context と呼ばれる gem を使用して、 shoulda/factory-girl テストを高速化する方法についての優れた投稿です。必要なものでない場合はお知らせください。

というプラグインがあります 高速コンテキスト (ギットハブのリンク) should ステートメントを 1 つのコンテキストに結合し、テストを高速化します。

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top