كيف يمكنني اختبار الاستثناء المتوقع برسالة استثناء محددة من ملف مورد في اختبار Visual Studio؟

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

سؤال

يمكن لاختبار Visual Studio التحقق من الاستثناءات المتوقعة باستخدام سمة اكسبيكتيدكسسيبشن.يمكنك تمرير استثناء مثل هذا:

[TestMethod]
[ExpectedException(typeof(CriticalException))]
public void GetOrganisation_MultipleOrganisations_ThrowsException()

يمكنك أيضًا التحقق من الرسالة الموجودة داخل ExceptedException مثل هذا:

[TestMethod]
[ExpectedException(typeof(CriticalException), "An error occured")]
public void GetOrganisation_MultipleOrganisations_ThrowsException()

ولكن عند اختبار تطبيقات I18N، سأستخدم ملف مورد للحصول على رسالة الخطأ هذه (قد يقرر أي شخص اختبار الترجمات المختلفة لرسالة الخطأ إذا أردت ذلك، لكن Visual Studio لن يسمح لي بذلك:

[TestMethod]
[ExpectedException(typeof(CriticalException), MyRes.MultipleOrganisationsNotAllowed)]
public void GetOrganisation_MultipleOrganisations_ThrowsException()

سيعطي المترجم الخطأ التالي:

يجب أن تكون وسيطة السمة تعبيرًا مستمرًا أو تعبيرًا من النوع أو تعبير إنشاء صفيف من سمة

هل يعرف أحد كيفية اختبار الاستثناء الذي يحتوي على رسالة من ملف مورد؟


أحد الخيارات التي فكرت فيها هو استخدام فئات الاستثناءات المخصصة، ولكن بناءً على النصائح التي يتم سماعها كثيرًا مثل:

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

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

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

المحلول

فقط رأي، ولكن أود أن أقول نص الخطأ:

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

لاحظ أن الخيار الأول يجب أن يتيح لك اختبار لغات متعددة، مع القدرة على التشغيل باستخدام لغة محلية.

أما بالنسبة للاستثناءات المتعددة، فأنا من أرض C++، حيث يكون إنشاء كميات كبيرة من الاستثناءات (إلى حد واحد لكل عبارة 'رمي'!) في التسلسلات الهرمية الكبيرة أمرًا مقبولًا (إن لم يكن شائعًا)، ولكن من المحتمل أن نظام البيانات الوصفية الخاص بـ .Net لا يفعل ذلك 'لا أحب ذلك، ومن هنا هذه النصيحة.

نصائح أخرى

أوصي باستخدام طريقة مساعدة بدلاً من السمة.شيء من هذا القبيل:

public static class ExceptionAssert
{
  public static T Throws<T>(Action action) where T : Exception
  {
    try
    {
      action();
    }
    catch (T ex)
    {
      return ex;
    }
    Assert.Fail("Exception of type {0} should be thrown.", typeof(T));

    //  The compiler doesn't know that Assert.Fail
    //  will always throw an exception
    return null;
  }
}

ثم يمكنك كتابة الاختبار الخاص بك بشيء من هذا القبيل:

[TestMethod]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
{
  OrganizationList organizations = new Organizations();
  organizations.Add(new Organization());
  organizations.Add(new Organization());

  var ex = ExceptionAssert.Throws<CriticalException>(
              () => organizations.GetOrganization());
  Assert.AreEqual(MyRes.MultipleOrganisationsNotAllowed, ex.Message);
}

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

لا تتطابق الوسيطة "الرسالة المتوقعة" مع رسالة الاستثناء.بل هذه هي الرسالة التي تتم طباعتها في نتائج الاختبار إذا لم يحدث الاستثناء المتوقع بالفعل.

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

إذا قمت بالتبديل إلى استخدام لطيف جدًا xUnit.Net مكتبة الاختبار، يمكنك استبدال [ExpectedException] بشيء مثل هذا:

[Fact]
public void TestException()
{
   Exception ex = Record.Exception(() => myClass.DoSomethingExceptional());
   // Assert whatever you like about the exception here.
}

أتساءل عما إذا كانت NUnit تتحرك في الطريق بعيدًا عن البساطة ...ولكن هنا تذهب.

تتيح لك التحسينات الجديدة (2.4.3 والإصدارات الأحدث) على سمة ExceptedException مزيدًا من التحكم في عمليات التحقق التي سيتم إجراؤها على الاستثناء المتوقع عبر طريقة المعالج.مزيد من التفاصيل على صفحة وثيقة NUnit الرسمية..في نهاية الصفحة.

[ExpectedException( Handler="HandlerMethod" )]
public void TestMethod()
{
...
}

public void HandlerMethod( System.Exception ex )
{
...
}

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

لقد صادفت هذا السؤال أثناء محاولتي حل مشكلة مماثلة بنفسي.(سأقوم بتفصيل الحل الذي استقرت عليه أدناه.)

يجب أن أتفق مع تعليقات Gishu حول تدويل رسائل الاستثناء كونها رائحة رمزية.

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

في مرحلة ما، كنت قد فكرت (واختبرت) في استخدام كتل المحاولة/التقاط لتجنب متطلبات الثابت بواسطة سمة ExceptedException، ولكن يبدو أن هذا سيؤدي إلى قدر كبير جدًا من التعليمات البرمجية الإضافية إذا تم تطبيقه على نطاق واسع.

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

يتلخص رمز الاختبار الخاص بي ببساطة في (العفو عن التشويه...):

[Test, 
    ExpectedException(typeof(System.ArgumentException),
    ExpectedException=ProductExceptionMessages.DuplicateProductName)]
public void TestCreateDuplicateProduct()
{
    _repository.CreateProduct("TestCreateDuplicateProduct");
    _repository.CreateProduct("TestCreateDuplicateProduct");
} 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top