Frage

ich nach einer Möglichkeit, meine Shoulda + factory Tests.

Das Modell Ich versuche zu testen (StudentExam) hat Assoziationen zu anderen Modellen. Diese assoziierten Objekte müssen vorhanden sein, bevor ich eine StudentExam erstellen können. Aus diesem Grunde werden sie in setup erstellt.

Doch eines unserer Modelle (School) nimmt viel Zeit zu erstellen. Da setup vor jeder should Anweisung aufgerufen wird, nimmt der gesamte Testfall Äonen auszuführen -. Eine neue @school schafft, @student, @topic und @exam für jede Anweisung ausgeführt sollte

ich nach einer Möglichkeit, diese Objekte einmal und nur einmal zu erstellen. Gibt es so etwas wie ein startup für before_all Methode, die mir erlauben würde, Datensätze zu erstellen, die für den Rest des Testfall anhalten wird?

Im Grunde suche ich nach etwas genau wie RSpec vor (: all) . Ich bin nicht besorgt über die Frage der Abhängigkeiten, da diese Tests werden nie die teueren Objekte ändern.

Hier ist ein Beispiel Testfall. Wir entschuldigen uns für den langen Code (Ich habe auch erstellt ein Kern ):

# 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
War es hilfreich?

Lösung

Wenn das Problem, diese Datensätze nur einmal schafft, können Sie eine Klassenvariable verwenden. Es ist kein sauberer Ansatz, aber zumindest sollte es funktionieren.

# 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

EDIT: Um die Super-hässliche Abhilfe fixiert die Auswertung mit einer Instanzmethode verschieben

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

Andere Tipps

Welche Art von Tests versuchen Sie zu schreiben? Wenn Sie tatsächlich sicherstellen möchten, dass alle diese Objekte entsprechend koordinieren, gerade schreiben Sie einen Integrationstest und die Geschwindigkeit ist nicht das primäre Anliegen. Wenn Sie jedoch zu Unit-Test des Modells sind versuchen, könnten Sie bessere Ergebnisse erzielen, indem aggressiv Anstoßen.

Zum Beispiel, wenn Sie zu überprüfen sind versuchen, dass eine Prüfung den Namen seines Schulverein verwendet, wenn Sie exam.location nennen (oder was auch immer Sie es sind anrufen), brauchen Sie nicht eine ganze Schule Objekt. Sie müssen nur sicherstellen, dass Prüfung die richtige Methode auf Schule ruft. Um zu testen, dass, könnten Sie so etwas wie die folgenden tun (mit Test :: Unit und Mokka, weil das ist, was ich kenne):

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

Grundsätzlich, wenn Sie Ihre Unit-Tests beschleunigen müssen, da Objekte zu teuer sind, zu konstruieren, sind Sie nicht wirklich Unit-Tests. Alle Testfälle oben fühlen, wie sie bei dem Unit-Test-Niveau, so dass Stummel Stummel Stummel!

sein sollten

http: // m .onkey.org / 2009/9/20 / Make-your-shoulda-Tests-schneller-mit-fast_context ist ein ausgezeichneter Beitrag darüber, wie Ihre shoulda / factory-Mädchen Tests schneller zu machen, ein Juwel namens fast_context mit . Lassen Sie uns wissen, wenn sie nicht das, was Sie brauchen.

Es gibt ein Plugin namens fast_context ( github Link ), die kombiniert sollten Anweisungen in einem einzigen Zusammenhang, die Tests zu beschleunigen .

Die andere Sache, die ich verwendet habe meine Tests zu beschleunigen, ist bereits bevölkert die Fixturedaten. Factory ist langsam, weil es die Datensätze jedes Mal, wenn der Setup-Block läuft zu schaffen.

Ich schrieb ein Plugin namens Fixie , die Activerecord verwendet, um die Testdatenbank vorab zu füllen, so dass die Datensätze, die Sie für Ihre Tests müssen bereits erstellt. Sie können Fixie benutzen zusammen mit factory wenn Sie neue Datensätze zur Laufzeit erstellt werden sollen, auch.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top