كيف أقوم باختبار الوحدة لطريقة تتوقع تحديث كائن عبر مرجع؟

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

  •  07-07-2019
  •  | 
  •  

سؤال

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

على سبيل المثال، لنفترض أن لدي فئة تسمى السياسة.

Policy policy = new Policy();
policy.Status = Active;

ثم أقوم بتمرير هذه السياسة إلى مدير السياسة من أجل إلغاء تنشيط السياسة.

policyManager.InactivatePolicy(policy);

تقوم طريقة سياسة إلغاء التنشيط بما يلي:

public void InactivatePolicy(Policy policy)
{
    policy.Status = Inactive;
    UpdatePolicy(policy); //saves the updated policy details via nhibernate
}

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

public void DoSomething(Policy policy)
{
    Policy policy = new Policy();
    policy.Status = Active;

    policyManager.InactivatePolicy(policy);
}

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

[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
    Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
    MyClass mc = new MyClass(policyManagerMock.Object);

    Policy policy = new Policy();
    policy.Status = Active;

    mc.DoSomething(policy);

    Assert.That(policy.Status, Is.EqualTo(Inactive)); //this fails      
}

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

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

public Policy InactivatePolicy(Policy policy)
{
    policy.Status = Inactive;
    UpdatePolicy(policy); //saves the updated policy details via nhibernate
    return policy;
}

[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
    Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
    MyClass mc = new MyClass(policyManagerMock.Object);

    Policy expectedInactivePolicy = new Policy();
    expectedInactivePolicy.Status = Inactive;

    Policy policy = new Policy();
    policy.Status = Active;

    policyManagerMock
        .Setup(p => p.InactivatePolicy(policy))
        .Returns(expectedInactivePolicy);   

    mc.DoSomething(policy);

    Assert.That(policy.Status, Is.EqualTo(Inactive)); //this now succeeds

}

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

هل يعرف أحد ما إذا كانت هناك طريقة أفضل للقيام بذلك؟هل يُجبر المرء بشكل أساسي على إرجاع القيم التي كان من المفترض في الأصل تحديثها عبر القيمة المرجعية التي تم تمريرها إلى الطريقة؟

هل من المحتمل أن تكون مشكلتي هي أن مدير السياسة لا ينبغي أن يكون لديه أسلوب InactivatePolicy ولكن يجب أن يكون بدلاً من ذلك على كائن السياسة نفسه ويتم استدعاء تحديث قاعدة البيانات لاحقًا؟

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

المحلول

لا ينبغي أن تسخر من PolicyManager، بل يجب أن تسخر من أسلوب UpdatePolicy لأنك لا تزال ترغب في اختبار وظيفة أسلوب DoSomething.

أيضًا، من المحتمل أنك تختبر مستوى عالٍ جدًا من الشجرة.

يجب عليك اختبار طريقة InactivatePolicy() بشكل منفصل واختبار أن الوظيفة تعمل فقط، ثم يجب عليك اختبار طريقة DoSomething()، مرة أخرى في العزل.

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

نصائح أخرى

متعرش

أنا لا أتابع تماما.

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

في أحسن الأحوال، سأفكر في إنشاء مخزن بيانات "محاكاة"؛لا السبات، وهذا لا يفعل شيئا.في هذه الحالة سيتم تنفيذه في UpdatePolicy فئة، مع بعض "MockRepo" بدلاً من "nHibernateRepo".

بهذه الطريقة، إذا قمت بإعداد الريبو بشكل مناسب، فيمكنك رؤيته قيد الإعداد.

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

ملخص

لماذا لا يكون لديك فقط قاعدة بيانات اختبارية يمكنك إجراء هذا الاختبار عليها؟

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

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