unit testing - اختبار وحدة أفضل الممارسات تسمية




unit-testing naming-conventions (8)

ما هي أفضل الممارسات لفئات اختبار وحدة التسمية وطرق الاختبار؟

وقد نوقش هذا على SO قبل ، في ما هي بعض اصطلاحات التسمية الشائعة لاختبارات وحدة؟

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

في فصول الاختبار الخاصة بي ، لديّ بعد ذلك أساليب تتضمن أسماء الطرق التي Save_ShouldThrowExceptionWithNullName() ، Save_ShouldThrowExceptionWithNullName() السفلي ، ثم الوضع وما أتوقع حدوثه ، على سبيل المثال Save_ShouldThrowExceptionWithNullName() .


أحب اتباع معيار "يجب" لتسمية الاختبارات أثناء تسمية أداة الاختبار بعد الوحدة تحت الاختبار (أي الفئة).

لتوضيح (باستخدام C # و NUnit):

[TestFixture]
public class BankAccountTests
{
  [Test]
  public void Should_Increase_Balance_When_Deposit_Is_Made()
  {
     var bankAccount = new BankAccount();
     bankAccount.Deposit(100);
     Assert.That(bankAccount.Balance, Is.EqualTo(100));
  }
}

لماذا "يجب" ؟

أجد أنه يجبر كتاب الاختبار على تسمية الاختبار بجملة على غرار "يجب [أن يكون في بعض الحالات] [بعد / قبل / متى] [العمل يحدث]"

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

تحديث :

لقد لاحظت أن جيمي بوجارد هو أيضًا من المعجبين بـ "يجب" ، ولديه أيضًا مكتبة اختبار وحدة تسمى " Should .

تحديث (بعد 4 سنوات ...)

للمهتمين ، تطورت تقاربي في تسمية الاختبارات على مر السنين. واحدة من القضايا مع نمط " ينبغي أن أصف" أعلاه ليس من السهل أن نعرف في لمحة الطريقة التي هي قيد الاختبار. ل OOP أعتقد أنه من المنطقي أن تبدأ اسم الاختبار بالطريقة تحت الاختبار. بالنسبة لفئة مصممة بشكل جيد ، يجب أن ينتج عن ذلك أسماء طرق اختبار قابلة للقراءة. يمكنني الآن استخدام تنسيق مشابه لـ <method>_Should<expected>_When<condition> . من الواضح أنه اعتماداً على السياق قد ترغب في استبدال الأفعال "يجب / عندما" لشيء أكثر ملاءمة. مثال: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()


أستخدم مفهوم Given-When-Then . إلقاء نظرة على هذا المقال القصير http://cakebaker.42dh.com/2009/05/28/given-when-then/ . تصف هذه المقالة هذا المفهوم من حيث BDD ، ولكن يمكنك استخدامه في TDD كذلك دون أي تغييرات.


أنا أحب استراتيجية تسمية روي Osherove ، هو ما يلي:

[UnitOfWork__StateUnderTest__ExpectedBehavior]

لديه كل المعلومات اللازمة عن اسم الأسلوب وبطريقة منظمة.

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

بالنسبة للتجميعات ، أستخدم .Tests النموذجية ، والتي أعتقد أنها منتشرة جدًا ونفس الشيء بالنسبة للفصول الدراسية (التي تنتهي Tests ):

[NameOfTheClassUnderTestTests]

في السابق كنت أستخدم Fixture كلاحقة بدلا من الاختبارات ولكن أعتقد أن هذا الأخير هو أكثر شيوعا ، ثم قمت بتغيير استراتيجية التسمية.



لقد توصلت مؤخرًا إلى الاتفاقية التالية لتسمية اختباراتي وفصولها واحتوائها على مشاريع بهدف زيادة عدد وصفاتها:

دعنا نقول إنني أختبر فئة الإعدادات في مشروع في مساحة الاسم MyApp.Serialization .

أولاً سأقوم بإنشاء مشروع اختبار مع مساحة الاسم MyApp.Serialization.Tests .

ضمن هذا المشروع وبالطبع مساحة الاسم سأقوم بإنشاء فئة تسمى IfSettings (المحفوظة باسم IfSettings.cs).

دعنا نقول إنني أختبر طريقة SaveStrings () . -> سأذكر اسم CanSaveStrings () .

عندما أقوم بإجراء هذا الاختبار ، سوف يظهر العنوان التالي:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

أعتقد أن هذا يخبرني بشكل جيد ، ما الذي تختبره.

بالطبع ، من المفيد أن تكون "الاختبارات" باللغة الإنجليزية هي نفسها "اختبارات" الفعل.

لا يوجد حد لإبداعك في تسمية الاختبارات ، حتى نحصل على عناوين الجملة الكاملة لهم.

عادة يجب أن تبدأ Testnames بفعل.

الامثله تشمل:

  • اكتشاف (على سبيل المثال DetectsInvalidUserInput)
  • يلقي (على سبيل المثال ThrowsOnNotFound)
  • سوف (على سبيل المثال WillCloseTheDatabaseAfterTheTransaction)

إلخ

خيار آخر هو استخدام "هذا" بدلاً من "إذا".

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

[ تحرير ]

بعد استخدام اصطلاح التسمية أعلاه لفترة أطول قليلا الآن ، لقد وجدت ، أن البادئة If يمكن أن تكون مربكة ، عند العمل مع واجهات. يحدث ذلك فقط ، أن فئة الاختبار IfSerializer.cs تبدو مشابهة جدا لواجهة ISerializer.cs في "فتح ملفات التبويب". يمكن أن يكون ذلك مزعجًا جدًا عند التبديل بين الاختبارات والاختبار والفئة التي يتم اختبارها وواجهة المستخدم. ونتيجة لذلك ، سأختار الآن أن أكثر إذا كان بمثابة بادئة.

بالإضافة إلى ذلك ، أستخدم الآن - فقط للطرق في فصول الاختبار الخاصة بي حيث لا يعتبر أفضل ممارسة في أي مكان آخر - "_" لفصل الكلمات في أسماء طرق الاختبار كما في:

  • [Test] public void detects_invalid_User_Input () *

أجد هذا أسهل في القراءة.

[ نهاية التعديل ]

آمل أن يؤدي هذا إلى المزيد من الأفكار ، لأنني أعتبر اختبارات التسمية ذات أهمية كبيرة لأنها يمكن أن توفر لك الكثير من الوقت الذي كان من الممكن أن يتم إنفاقه في محاولة فهم ما تقوم به الاختبارات (على سبيل المثال بعد استئناف المشروع بعد فترة توقف ممتدة) .


يجب أن يكون اسم حالة الاختبار للفئة Foo هو FooTestCase أو ما شابه ذلك (FooIntegrationTestCase أو FooAcceptanceTestCase) - نظرًا لأنها حالة اختبار. راجع http://xunitpatterns.com/ لبعض اصطلاحات التسمية القياسية مثل الاختبار ، وحالة الاختبار ، ومثبت الاختبار ، وطريقة الاختبار ، وما إلى ذلك.


يقترح كينت بيك :

  • اختبار واحد لكل "وحدة" (صنف برنامجك). تركيبات اختبار هي الطبقات نفسها. يجب أن يكون اسم لاعبا الاختبار هو:

    [name of your 'unit']Tests
    
  • حالات الاختبار (طرق اختبار الاختبار) لها أسماء مثل:

    test[feature being tested]
    

على سبيل المثال ، وجود الصف التالي:

class Person {
    int calculateAge() { ... }

    // other methods and properties
}

سيكون اختبار الاختبار:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

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

أنا شخصيا أحب أفضل الممارسات التي تم وصفها في "JUnit Pocket Guide" ... من الصعب الفوز على كتاب كتبه المؤلف المشارك في JUnit!







naming-conventions