سؤال

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

هل من الممكن اكتشاف أن أحد الاختبارات فشل وأداء نوع من التنظيف؟

لا نريد كتابة رمز التنظيف في كل اختبار، ونحن نقوم بذلك الآن. أرغب في تنظيف Perfrom في Teardown ولكن فقط إذا فشل الاختبار، لأن التنظيف قد يكون مكلفا.

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

تحديث 2.:

        [Test]
        public void MyFailTest()
        {
            throw new InvalidOperationException();
        }

        [Test]
        public void MySuccessTest()
        {
            Assert.That(true, Is.True);
        }

        [TearDown]
        public void CleanUpOnError()
        {
            if (HasLastTestFailed()) CleanUpDatabase();
        }

أنا أبحث عن تنفيذ haslasttestfailed ()

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

المحلول

هذه الفكرة حصلت لي مهتمة، لذلك فعلت حفر قليلا. لا يحتوي NUNIT على هذه القدرة خارج الصندوق، ولكن هناك إطار قابل للتمويل بأكمله يتم توفيره مع NUNIT. وجدت هذه المادة الرائعة حول تمديد nunit - كانت نقطة انطلاق جيدة. بعد اللعب معها، توصلت إلى الحل التالي: طريقة مزينة حسب الطلب CleanupOnError سيتم استدعاء السمة إذا فشل أحد الاختبارات في المباراة.

إليكم كيف يشبه الاختبار:

  [TestFixture]
  public class NUnitAddinTest
  {
    [CleanupOnError]
    public static void CleanupOnError()
    {
      Console.WriteLine("There was an error, cleaning up...");
      // perform cleanup logic
    }

    [Test]
    public void Test1_this_test_passes()
    {
      Console.WriteLine("Hello from Test1");
    }

    [Test]
    public void Test2_this_test_fails()
    {
      throw new Exception("Test2 failed");
    }

    [Test]
    public void Test3_this_test_passes()
    {
      Console.WriteLine("Hello from Test3");
    }
  }

حيث السمة هي ببساطة:

  [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
  public sealed class CleanupOnErrorAttribute : Attribute
  {
  }

وهنا كيفية تنفيذها من Addin:

public void RunFinished(TestResult result)
{
  if (result.IsFailure)
  {
    if (_CurrentFixture != null)
    {
      MethodInfo[] methods = Reflect.GetMethodsWithAttribute(_CurrentFixture.FixtureType,
                                                             CleanupAttributeFullName, false);
      if (methods == null || methods.Length == 0)
      {
        return;
      }

      Reflect.InvokeMethod(methods[0], _CurrentFixture);
    }
  }
}

ولكن هنا الجزء الصعب: يجب وضع Addin في addins الدليل بجانب عداء nunit. تم وضع الألغام بجانب عداء Nunit في دليل TestDriven.net:

C:\Program Files\TestDriven.NET 2.0\NUnit\addins

(أنا خلقت addins دليل، لم يكن هناك)

تعديل شيء آخر هو أن طريقة التنظيف يجب أن تكون static!

اخترقت معا Addin بسيط، يمكنك تنزيل المصدر من بلدي skydrive. وبعد سيكون لديك لإضافة مراجع إلى nunit.framework.dll, nunit.core.dll و nunit.core.interfaces.dll في الأماكن المناسبة.

بعض الملاحظات: يمكن وضع فئة السمة في أي مكان في التعليمات البرمجية الخاصة بك. لم أكن أرغب في وضعه في نفس التجميع مثل Addin نفسه، لأنه يشير إلى اثنين Core جمعيات nunit، لذلك وضعت ذلك في مجموعة مختلفة. فقط تذكر تغيير الخط في CleanAddin.cs, ، إذا قررت وضعه في أي مكان آخر.

امل ان يساعد.

نصائح أخرى

منذ الإصدار 2.5.7، يسمح Nunit بالدموع في حالة فشل الاختبار الأخير. تتيح فئة TestContext الجديدة الاختبارات للوصول إلى معلومات عن نفسها بما في ذلك Teststauts.

لمزيد من التفاصيل، يرجى الرجوع إلى http://nunit.org/؟p=releasenotes&r=2.5.7.

[TearDown]
public void TearDown()
{
    if (TestContext.CurrentContext.Result.Status == TestStatus.Failed)
    {
        PerformCleanUpFromTest();
    }
}

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

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

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

يتم استخدام هذه السمة داخل جهاز اختبار لتوفير مجموعة مشتركة من الوظائف التي يتم تنفيذها بعد تشغيل كل طريقة اختبار.

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

رغم ذلك، أراها أيضا أنك لا تريد أي رمز معقد منطق أو خطأ في التعامل مع الأخطاء.

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

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

ماذا عن استخدام كتلة المحاولة، وإعادة النظر في الاستثناء الذي اشتعلت؟

try
{
//Some assertion
}
catch
{
     CleanUpMethod();
     throw;
}

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

ستتمكن أيضا من اختبار استثناءك أفضل بكثير.

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

public abstract class CleanOnErrorFixture
{
     protected bool threwException = false;

     protected void ThrowException(Exception someException)
     {
         threwException = true;
         throw someException;
     }

     protected bool HasTestFailed()
     {
          if(threwException)
          {
               threwException = false; //So that this is reset after each teardown
               return true;
          }
          return false;
     }
}

ثم استخدام مثالك:

[TestFixture]
public class SomeFixture : CleanOnErrorFixture
{
    [Test]
    public void MyFailTest()
    {
        ThrowException(new InvalidOperationException());
    }

    [Test]
    public void MySuccessTest()
    {
        Assert.That(true, Is.True);
    }

    [TearDown]
    public void CleanUpOnError()
    {
        if (HasLastTestFailed()) CleanUpDatabase();
    }
}

المشكلة الوحيدة هنا هي أن تتبع المكدس سيؤدي إلى cleanonerrororfixture

أحد الخيارات غير المذكورة حتى الآن هو التفاف اختبار أعلى في كائن المعاملات المعاملات، لذلك لا يهم ما يحدث حيث لا يختفي الاختبار أبدا أي شيء إلى DB.

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

هذا النهج بسيط، لا يتطلب أي تنظيف ويضمن أن الاختبارات معزولة.

تحرير - لقد لاحظت أن إجابة راي هايز تشبه أيضا لي.

كيف يفشل؟ هل من الممكن وضعه في محاولة (اختبار) / الصيد (إصلاح كسر DB) / أخيرا كتلة؟

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

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

باستخدام هذين الحقائق التي يمكنك كتابتها مثل تحديد العلم إذا فشل الاختبارات وفحص قيمة العلم في اختبار المسيل للدموع.

أنا لا أوصي بهذا، لكنه سيعمل. أنت لا تستخدم حقا nunit كما هو المقصود، ولكن يمكنك القيام بذلك.


[TestFixture]
public class Tests {
     private bool testsFailed = false;

     [Test]
     public void ATest() {
         try {
             DoSomething();
             Assert.AreEqual(....);
         } catch {
            testFailed = true;
         }
     }

     [TestFixtureTearDown]
     public void CleanUp() {
          if (testsFailed) {
              DoCleanup();
          }
     }
}

يمكنك إضافة [TearDown] طريقة مع
if (TestContext.CurrentContext.Result.Status != TestStatus.Passed)
يتم تنفيذ بعض الكود إذا فشل الاختبار.

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