هل من المقبول تشغيل الحلقات في طرق الاختبار الوظيفية؟

StackOverflow https://stackoverflow.com/questions/1789834

سؤال

هل من المقبول (من الناحية المفاهيمية) تشغيل الحلقات في طرق الاختبار؟

أرغب في اختبار مجموعة من قيم المعلمة في وحدة تحكم ، لتحديد ما إذا كانت المدخلات المختلفة تُرجع القيم الصحيحة.

  test "logged in user - add something - 0 qty" do
    @app = Factory.create(:app)

    (0..5).each do |t|
      @qty = t
      login(:user)
      get :add. :id => @app.id, :qty => @qty
      assert_nil(flash[:error])
      assert_response :redirect
      assert_redirect_to :controller => :apps, :action => :show, :id => @app.id
      if @qty = 0 
        assert_equal(Invite.all.count, @qty + 1)
      else 
        assert_something .........
    end
  end

شئ مثل هذا.

هل كانت مفيدة؟

المحلول

عادةً ما أحاول تجنب أي نوع من البيانات الشرطية أو الحلقات في رمز الاختبار. تريد أن تكون اختباراتك بسيطة قدر الإمكان ، وإذا بدأت في تضمين المنطق في الاختبارات الخاصة بك ، يجب عليك اختبار معهم للتأكد من أنها تعمل كما تم تصميمها. أود أن أقوم بتقسيم الحلقة إلى حالات اختبار منفصلة ، وبهذه الطريقة إذا فشل أي منها ، فمن الأسهل تحديد ما تسببت المدخلات في الفشل. عندما يفشل الاختبار ، يجب أن يكون من الواضح على الفور سبب ذلك. يجب ألا تضطر إلى تحليل رمز الاختبار لمعرفة ذلك.

تحديث:

أريد أن أضيف أن هناك بعض نادر للغاية الحالات التي ترغب في الحصول عليها في حالات الاختبار. أحد الأمثلة المحددة هو عندما تختبر مشكلات التزامن. هذا استثناء للقاعدة العامة ، ويجب أن يكون لديك سبب جيد للغاية وفهم جيدًا لوجود أي نوع من المنطق في اختباراتك.

نصائح أخرى

هل من المقبول (من الناحية المفاهيمية) تشغيل الحلقات في طرق الاختبار؟

تقصد ، هل هو صحيح سياسيا؟

يعمل ، أليس كذلك؟ أحاول أن أتخيل ماهية الاعتراض.

يجب أيضًا النظر إلى الاختبارات على أنها "وثائق حية" لـ ماذا او ما من المفترض أن يفعل البرنامج الخاص بك ، لذلك اجعلها واضحة قدر الإمكان.

ليس من الصحيح من الناحية السياسية استخدام أكثر من تأكيد أو التحقق من الصحة في كل اختبار. ومع ذلك ، الجميع يفعل ذلك. يظهر أحد الأنماط الجديدة في سيناريوهات اختبار Cucumber حيث لا يزال السيناريو بتنسيق قابل للقراءة للغاية ولكنه يسمح باختبار مجموعات متعددة من البيانات.

لكنها روبي ، لن تستخدمه إذا كنت من النوع الذي يتبع إرشادات أي شخص آخر إلى الرسالة. لا توجد طريقة صحيحة ، فقط الأكثر شيوعًا وهذا يتغير كثيرًا.

سألت ذات مرة طبيب الأسنان عن أي ترتيب يجب أن أقوم بالفرشاة والخيط والشطف. أخبرني أنه لا يهتم إذا تمكنت من فعل الثلاثة بالفعل. أعتقد أن النقطة كانت في كثير من الأحيان أن التطبيقات دون المستوى المطلوب أفضل من لا شيء على الإطلاق. إذا كانت الحلقات تجعل الاختبار أكثر متعة ، وبالتالي على الأرجح ، فيجب عليك حلق الجحيم المقدس من اختباراتك.

من الأفضل أن يكون لديك إطار عملك تدرك أن هذا الاختبار الواحد يقوم بالفعل بإجراء اختبارات متعددة (مع معلمات مختلفة). يتيح لك معرفة ما فشل مجموعة المعلمة الدقيقة والتي تنجح في تقرير الاختبار.

قد تكون هناك حالات تحتاج فيها إلى حلقات ولكنك ليست ضرورية واحدة منها. تذكر أن إضافة المزيد من التعقيد إلى الاختبارات يجعل من الصعب العمل معهم. عندما يتطور التطبيق اختبارات تتطور أيضًا. إذا جعلتها معقدة للغاية في البداية ، من يوم واحد قد تواجه خيارًا:

  • هل يجب أن أقضي 3 أيام لإعادة تشكيل هذا الاختبار القديم الكبير الذي يفشل؟
  • هل يجب حذف الاختبار وكتابة أنيقة جديدة أبسط (في 3،5 يوم)؟

هذا هو الخيار الصعب. في الخيار الأول ، تضيع الوقت لتنفيذ ميزات جديدة لشيء لا يدفع المشروع إلى الأمام؟ هل لديك وقت لهذا؟ هل يعتقد مديرك أن لديك وقت لهذا؟ هل يدفع العميل مقابل وقتك في هذا المشروع أن لديك وقتًا لهذا؟
تتميز طبقات الخيار الثاني بأن تكون معقولة ، ولكن عند كتابة اختبارات جديدة ، كيف تعرف أنك غطيت جميع الحالات كحالات قديمة (بالإضافة إلى حالات جديدة)؟ هل كل شيء في الوثائق؟ هل هو في وثائق الاختبار؟ هل تتذكر كل منهم؟ أو ربما تمر عبر رمز الاختبار وإعادة تشكيله للكشف عن جميع الحالات المخفية داخل هذه الكود؟ أليس هذا الخيار الأول؟

لا تجري اختبارات مثل الرمز القديم. رمز لا أحد يريد أن يلمس ، لا أحد يعرفه حقًا ، كل شخص يحاول تجنبه وتجاهله قدر الإمكان. يجب تصميم الاختبارات كتطبيق REST. قم بتطبيق العديد من مبادئ التصميم أثناء تطبيقك على تصميم التعليمات البرمجية. اجعلها بسيطة. مسؤولية منفصلة. تجميعها منطقيا. اجعلها سهلة لإعادة تشكيلها. اجعلها قابلة للتمديد. هناك أشياء كثيرة يجب أن تأخذها في الاعتبار.

أما بالنسبة لحالتك. دعنا نفترض أن لديك حالة استخدام حيث يقوم الرمز الخاص بك بشيء للمعلمة في <0،100> (0..5 من الكود الخاص بك قريب ، يبدو مثال أكثر وضوحًا عند استخدام نطاق أوسع). في القيم الأخرى ، يقوم ببعض معالجة الاستثناءات. في هذه الحالة ، تريد حالات الاختبار:

  • عندما المعلمة = -1
  • عندما المعلمة = 0
  • عندما المعلمة = 1
  • عندما المعلمة = 99
  • عندما المعلمة = 100
  • عندما المعلمة = 101

حالات اختبار بسيطة منفصلة يسهل إعادة تجديدها ، سهلة القراءة مع استمرار التحقق من التعليمات البرمجية بشكل صحيح.
يمكنك إضافة حالة اختبار حيث يمكنك استخدام Loop للتحقق من السلوك عندما تكون المعلمة في (10،70) ولكن لا ينصح بها. مع وجود الكثير من الاختبارات والمعلمات الواسعة ، فإنه مجرد مضيعة للموارد. إذا كانت الخوارزمية حتمية ، فهل تقوم نفس الخطوات لبعض مجموعة القيم التي ستعمل عليها جميعًا إذا كانت تعمل من أجل واحدة.
حاول أن تقرأ عن فئات التكافؤ ، والقيم الحدودية ، والاختبار الزوجي ، وتغطية المسار ، وتغطية العبارات ، وتغطية الفرع ، وتقنيات الاختبار الأخرى لجعل اختباراتك أفضل.

سأضيف نفسي إلى قائمة غير الصحيح من الناحية السياسية. عند اختبار مجموعة من القيم ، يمكن للحلقة أن تزيد من قابلية اختبار الاختبار. علاوة على ذلك ، فإنه يساعد على جفاف ، مما يجعل إعادة الطرد أسهل: هل تفضل إضافة المعلمة الجديدة إلى الأماكن الثمانية التي يتم استدعاء الطريقة في الاختبار ، أو إلى واحدة فقط؟

إليك اختبار يستخدم هذه التقنية. إنها تستخدم مكتبة اختبار محلية ، لكن التقنية عالمية:

  def test_swap_name
    test_cases = [
      [
        'Paul, Ron P.A.',
        'Ron Paul PA'
      ],
      [
        "PUBLIC, SR., JOHN Q",
        "JOHN Q PUBLIC SR"
      ],
      [
        "SMITH, JR., MARK A",
        "MARK A SMITH JR"
      ],
      [
        'James Brown',
        'James Brown'
      ],
      # (more test cases)
    ]
    for original, swapped in test_cases
      assertInfo("For original = #{original.inspect}") do
        assertEquals(original.swap_name, swapped)
      end
    end
  end

يضيف AssertInfo سلسلة تعسفية إلى بداية أي رسالة استثناء. هكذا يمكنك أن تعرف ، عندما فشل الاختبار ، تم اختبار البيانات:

./StringUtil.test.rb
Method "test_swap_name" failed:
Assert::BlownAssert: For original = "Paul, Ron P.A.": Expected:
"Ron Paul PA"
but got
"Paul, Ron P.A."
./../../testlib/Assert.rb:125:in `fail_test'
./../../testlib/Assert.rb:43:in `assertEquals'
./StringUtil.test.rb:627:in `test_swap_name'

أنا موافق بشكل عام مع حلقة في اختبار طالما أن هناك حدوث واحد فقط للتأكيد في الاختبار. بمعنى آخر ، هذا جيد:

test "something" do
  for item in @collection
    assert_something item
  end
end

لكن هذا ليس:

test "something" do
  for item in @collection
    assert_something item
    assert_something_else item
  end
end

وهذه ستجعلك تكره نفسك:

test "something" do
  for item in @collection
    assert_something item
    if x == y
      assert_something_else item
    end
  end
end

test "something" do
  for item in @collection
    assert_something item
  end
  for item in @collection
    assert_something_else item
  end
end

والوقت الوحيد الذي سأكتب فيه اختبارًا بهذه الطريقة هو ما إذا كانت العناصر الموجودة في المجموعة تختلف من بعضها البعض بشكل كبير ، ولكن كان هناك بعض الحاجة للتحقق من السلوك المشترك بشكل شائع. على سبيل المثال ، قد يكون لديك عشر حالات من الأشياء المختلفة ، لكن من المفترض أن تستجيب جميعًا لبعض الرسائل. لذلك يمكنك التحقق من أن جميع الحالات يمكن أن تفعل الشيء الذي من المفترض أن تفعله الطريقة التي تتميز بها البط. ولكن إذا كان لديك مجموعة تحتوي دائمًا على حالات Foo, ، غالبًا ما تكون أفضل حالًا في التأكيد على @collection.first. يتم تنفيذ الاختبار بشكل أسرع ، وأنت لا تكتسب الكثير من تكرار التأكيد على جميع الحالات ، وفي معظم الحالات ، من الأفضل أن تختبر مجرد اختبار item بمعزل عن بقية المجموعة على أي حال. إذا كنت تشعر بجنون العظمة بشكل خاص ، فهذا جيد بشكل عام:

test "items are all Foo" do
  for item in @collection
    assert_kind_of Foo, item, "Everything in @collection must be Foo."
  end
end
test "something" do
  assert_something @collection.first
end

سوف يفشل اختبار "شيء ما" على أي حال إذا لم تكن لديكFoo الكائنات في المجموعة ، ولكن الاختبار السابق يجعل من الواضح أن المشكلة الحقيقية هي.

باختصار ، تجنب ذلك ، ولكن إذا كان لديك سبب وجيه للقيام بذلك ، فاملا. وإذا أصبحت مشكلة على الطريق ، فيجب أن يكون الاختبار بسيطًا بما يكفي بحيث يكون إعادة تمثيله إلى شيء أقل مشكلة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top