يجب أن + factorygirl: هل يمكنني إجراء اختباراتي بشكل أسرع؟
-
13-09-2019 - |
سؤال
أنا أبحث عن وسيلة لتسريع بلدي صراحة + فتاة المصنع اختبارات.
النموذج الذي أحاول اختباره (StudentExam
) لديه جمعيات إلى نماذج أخرى. يجب أن تكون هذه الكائنات المرتبطة موجودة قبل أن أتمكن من إنشاء StudentExam
. وبعد لهذا السبب، يتم إنشاؤها في setup
.
ومع ذلك، واحدة من نماذجنا (School
) يأخذ وقتا كبيرا لإنشاء. لان setup
يحصل دعا من قبل كل should
البيان، فإن حالة الاختبار بأكملها تأخذ eons لتنفيذ - إنه يخلق جديد @school
, @student
, @topic
و @exam
لكل بيان تنفيذها.
أبحث عن طريقة لإنشاء هذه الكائنات مرة واحدة وفقط مرة واحدة فقط. وبعد هل هناك شيء مثل 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
المحلول
إذا كانت المشكلة تقوم بإنشاء هذه السجلات مرة واحدة فقط، فيمكنك استخدام متغير فئة. إنه ليس نهج نظيف ولكن على الأقل يجب أن تعمل.
# 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
نصائح أخرى
أي نوع من الاختبارات تحاول الكتابة؟ إذا كنت ترغب بالفعل في التأكد من أن كل هذه الكائنات تنسق بشكل مناسب، فأنت تكتب اختبار التكامل والسرعة ليست مصدر قلقك الأساسي. ومع ذلك، إذا كنت تحاول وحدة اختبار النموذج، فيمكنك تحقيق نتائج أفضل من قبل stubbing بقوة.
على سبيل المثال، إذا كنت تحاول التحقق من أن الامتحان يستخدم اسم جمعية مدرسته عند الاتصال بالامتحان. الموقع (أو ما كنت تتصل به)، فلن تحتاج إلى كائن مدرسة بأكمله. تحتاج فقط إلى التأكد من أن الامتحان يدعو الطريقة الصحيحة في المدرسة. لاختبار ذلك، يمكنك القيام بشيء مثل ما يلي (باستخدام الاختبار :: وحدة ومخي لأن هذا ما أعرفه):
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-ast_context. هو منشور ممتاز حول كيفية جعل اختبارات فتات المصنع / المصنع الخاصة بك بشكل أسرع، باستخدام جوهرة يسمى fast_context. اسمحوا لي أن أعرف إذا لم يكن ما تحتاجه.
هناك مكون إضافي يسمى fast_context. (رابط جيثب) يجمع بين التصريحات في سياق واحد، وتسريع الاختبارات.
الشيء الآخر الذي كنت أستخدمه لتسريع اختباراتي هو ما قبل ملء بيانات المباراة. FactoryGirl بطيء لأنه يخلق هذه السجلات في كل مرة يعمل فيها كتلة الإعداد.
كتبت مكونا مكونا يسمى fixie. يستخدم هذا activerecord لملء قاعدة بيانات الاختبار مسبقا، لذلك يتم إنشاء السجلات التي تحتاجها للاختبارات الخاصة بك بالفعل. يمكنك استخدام Fixie جنبا إلى جنب مع FactoryGirl إذا كنت ترغب في إنشاء سجلات جديدة في وقت التشغيل، أيضا.