Domanda

Sto cercando un modo per velocizzare il mio Avrei dovuto + Operaia test.

Il modello che sto cercando di testare (StudentExam) ha associazioni con altri modelli.Questi oggetti associati devono esistere prima di poter creare un file StudentExam.Per questo motivo vengono creati in setup.

Tuttavia, uno dei nostri modelli (School) richiede molto tempo per essere creato.Perché setup viene chiamato prima di ogni should istruzione, l'intero test case richiede eoni per essere eseguito: crea un nuovo @school, @student, @topic E @exam per ogni istruzione dovrebbe essere eseguita.

Sto cercando un modo per creare questi oggetti una volta e solo una volta.C'è qualcosa come a startup per before_all metodo che mi consentirebbe di creare record che persisteranno per tutto il resto del test case?

Fondamentalmente sto cercando qualcosa esattamente come quello di RSpec prima(:tutto).Non sono preoccupato per il problema delle dipendenze poiché questi test non modificheranno mai quegli oggetti costosi.

Ecco un esempio di caso di test.Ci scusiamo per il codice lungo (ho anche creato un file sostanza):

# 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
È stato utile?

Soluzione

Se il problema riguarda la creazione di questi record solo una volta, è possibile utilizzare una variabile di classe.Non è un approccio pulito ma almeno dovrebbe funzionare.

# 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

MODIFICARE:Per risolvere la soluzione estremamente brutta, rinviare la valutazione con un metodo di istanza.

# 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

Altri suggerimenti

Che tipo di test stai cercando di scrivere?Se vuoi davvero assicurarti che tutti questi oggetti siano coordinati in modo appropriato, stai scrivendo un test di integrazione e la velocità non è la tua preoccupazione principale.Tuttavia, se stai provando a testare l'unità del modello, potresti ottenere risultati migliori effettuando uno stubbing aggressivo.

Ad esempio, se stai cercando di verificare che un esame utilizzi il nome della sua associazione scolastica quando chiami exam.location (o come lo chiami), non hai bisogno di un intero oggetto scolastico.Devi solo assicurarti che l'esame chiami il metodo giusto a scuola.Per testarlo, potresti fare qualcosa di simile (usando Test::Unit e Mocha perché è quello con cui ho familiarità):

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

Fondamentalmente, se hai bisogno di accelerare i test unitari perché gli oggetti sono troppo costosi da costruire, non stai effettivamente testando le unità.Tutti i casi di test sopra riportati sembrano dovrebbero essere a livello di test unitario, quindi stub stub!

http://m.onkey.org/2009/9/20/make-your-shoulda-tests-faster-with-fast_context è un post eccellente su come rendere più veloci i tuoi test Shoulda/factory-girl, utilizzando un gioiello chiamato fast_context.Fammi sapere se non è quello che ti serve.

C'è un plugin chiamato contesto_veloce (collegamento github) che unisce le istruzioni dovrebbero in un unico contesto, velocizzando i test.

L'altra cosa che utilizzo per velocizzare i miei test è precompilare i dati delle partite.FactoryGirl è lenta perché crea tali record ogni volta che viene eseguito il blocco di installazione.

Ho scritto un plugin chiamato Fixie che utilizza ActiveRecord per precompilare il database dei test, quindi i record necessari per i test sono già creati.Puoi utilizzare Fixie insieme a FactoryGirl se desideri creare nuovi record anche in fase di esecuzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top