Autofixture: NSubstitute.ReceivedCalls () إرجاع قيمة خاطئة باستخدام AutoFixture.AutoNSubstitute

تم إنشاؤها على ٢٨ مارس ٢٠١٨  ·  10تعليقات  ·  مصدر: AutoFixture/AutoFixture

لدينا الكثير من الاختبارات باستخدام 'Class.ReceivedCalls ()' و 'var tmp = Class.Received (int) .Property؛' للتحقق من عدد المكالمات. في الإصدار 3 من AutoFixture ، أبلغت بشكل صحيح عن عدد المكالمات ، خاصةً في الخصائص ، والتي لم تعد تفعلها بعد الآن. يبدو أن عدد استدعاء الأساليب لا يزال على ما يرام.
بالنظر إلى أن لدينا الكود التالي:

    public interface IRunSpeed
    {
        int Speed { get; }
    }

    public class GetToDaChoppa
    {
        private readonly IRunSpeed _runSpeed;

        public GetToDaChoppa(IRunSpeed runSpeed)
        {
            _runSpeed = runSpeed ?? throw new ArgumentNullException(nameof(runSpeed));
        }

        public void DoItNow()
        {
            var runningSpeed = _runSpeed.Speed;
        }
    }

وعلمًا بأن لدينا الفحوصات التالية:

        [Fact]
        public void DoItNow_WithOutAutoNSubstitute()
        {
            // Arrange
            var runSpeed = Substitute.For<IRunSpeed>();
            runSpeed.Speed.Returns(2);

            var sut = new GetToDaChoppa(runSpeed);

            //Act
            sut.DoItNow();

            //Assert
            var tmp = runSpeed.Received(1).Speed;
            Assert.Single(runSpeed.ReceivedCalls());
        }

        [Theory, AutoNSubstituteData]
        public void DoItNow_UsingAutoNSubstitute(
            [Frozen] IRunSpeed runSpeed,
            GetToDaChoppa sut)
        {
            // Arrange
            runSpeed.Speed.Returns(49);

            //Act
            sut.DoItNow();

            //Assert
            var tmp = runSpeed.Received(1).Speed;
            Assert.Single(runSpeed.ReceivedCalls());

تبدو سمة DataAttribute الخاصة بي كما يلي:

        public class AutoNSubstituteDataAttribute : AutoDataAttribute
        {
            public AutoNSubstituteDataAttribute()
                : base(() => new Fixture()
                           .Customize(new AutoNSubstituteCustomization()))
            {
            }
        }

الاختبار الأول "DoItNow_WithOutAutoNSubstitute" يعمل بشكل جيد. لكن الاختبار الثاني "DoItNow_UsingAutoNubstitute" يعيد 2 لـ "ios.Received (1) .Speed؛".
تقوم أيضًا بإرجاع 2 لـ 'runSpeed.ReceivedCalls () ؛'.
لهذا السبب ، لا يمكننا حاليًا ترقية حلولنا إلى الإصدار 4 نظرًا لأن لدينا على الفور> 1000 اختبار فاشل لكل حل. هل توجد أي إرشادات حول ماهية المشكلة أو مكان البحث عن الإصلاح؟

question

ال 10 كومينتر

شكرا لطرد القضية. في الواقع ، هذه المشكلة لا علاقة لها بالتثبيت التلقائي ، بينما نتأثر بها أيضًا 😕

تحدث هذه المشكلة في الغالب بسبب xUnit وإذا أعدت كتابة الاختبار على النحو التالي ، فسيتم اجتيازه:
ج #
[نظرية ، بيانات الاستبدال التلقائي]
باطل عام DoItNow_UsingAutoNSubstitute_Create يدويًا (IFixture fixture)
{
// رتب
var runSpeed ​​= تركيبات. تجميد() ؛
var sut = fixture.Create() ؛
runSpeed.Speed.Returns (49) ،

//Act
sut.DoItNow();

//Assert
var tmp = runSpeed.Received(1).Speed;
Assert.Single(runSpeed.ReceivedCalls());

}
""

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

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

من الغريب أنك لم تواجه هذه المشكلة مع الإصدار 3 ، حيث لم يتغير شيء في هذا الصدد. لقد اختبرت للتو xUnit2 + AutoFixture v3 وما زلت أواجه المشكلة. ربما قمت بترقية xUnit أيضًا.


بالنسبة للحل البديل ، لدي أخبار جيدة وسيئة. والخبر السار هو أنه سيتم حل هذه المشكلة في الإصدار الرئيسي التالي من NSubsitute ، حيث بدأ في تجاوز طريقة ToString() لإرجاع معرف الوكيل. نتيجة لذلك ، لم تعد xUnit تلمس الخصائص بعد الآن:
image

النبأ السيئ هو أن NSubsitute v4 لم يتم إصداره بعد.

يمكنني أن أقترح عليك إما:

  • تأجيل الترحيل حتى إصدار NSubsitute v4 ؛
  • استخدم أحدث كود مصدر master لـ NSubsitute ، وقم بإنشاء بنية محلية واستخدم NSubsitute.dll الخاص بك بدلاً من حزمة NuGet. بعد إصدار v4 ، يمكنك التبديل إلى حزمة NuGet.
  • إذا قمت بتحديث إصدار xUnit أيضًا (لأن هذا قد يفسر سبب عدم وجود هذه المشكلة من قبل) ، فارجع عن هذا التغيير واستخدم الإصدار السابق من xUnit.

أعتذر عن الإزعاج ، لكن للأسف لا يمكننا فعل أي شيء من جانب AutoFixture لإصلاح هذه المشكلة.

فقط اختبرت هذا. أخيرًا ، عادت اختباراتنا التي تؤكد أن ReceivedCalls للحصول على نتيجة ناجحة مرة أخرى.
الشيء الذي لا يزال يفشل هو التأكيدات على Received (x) مثل Received (1) .Speed ​​Daniel المذكور أعلاه.

snip_20180328181559

هل لديك أيضًا إجابة / حل للقبعة؟

هل تعملون في نفس المشروع يا رفاق؟ :) إذا كان الأمر كذلك ، فهل يمكنك توضيح كيفية إصلاح المشكلة؟

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

ليس في الواقع نفس المشروع ولكن في نفس الشركة.
لقد استخدمنا xunit 1.9 + nsubstitute 2/3 لفترة طويلة وتمكنا أخيرًا من الحصول على تجميعاتنا الداخلية (حزم nuget لذا فإن طريقة بسيطة للعودة إلى إصدار أقدم من مرجع واحد ليس سهلاً كما يبدو لتكون) لتكون متوافقة مع xunit2. والآن لدينا هاتان المشكلتان.

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

تمامًا كما وصفت أعلاه ، قمت باستبدال مرجع nuget 3.1 بالمرجع من مشروع nsubstitute المترجم حديثًا. بعد ذلك ، لدي الآن 118 اختبارًا فاشلاً بدلاً من 178 اختبارًا بسبب Received (x) لا يزال يقيم عددًا خاطئًا من المكالمات.

يعتمد مشروعي حاليًا على .net 4.5.2 مع xunit2 ، نسخة الريبو الحالية من nsubstitute و autofixture 4.2 المشار إليها. فشلت جميع الاختبارات لنفس السببين - كما لا تزال هناك بعض المكالمات المستلمة التي فشلت في اختبارات الوحدة.
أعتقد أنني يجب أن ألقي نظرة أعمق عليه مرة أخرى عندما أعود إلى المكتب مرة أخرى (في الخارج لعيد الفصح).
ربما يستطيعdklinger في الوقت نفسه وصف السيناريو.

dklingerevilbaschdi الرجاء متابعة بعد لديك فرصة للتحقق ذلك - انها مثيرة للاهتمام الى حد بعيد لماذا عتبة رؤية القضايا، حتى بعد تطبيق التصحيح.

أعد فتح المشكلة للإشارة إلى أنه لا يزال لدينا تحقيق مستمر.

حسنًا ، لقد اختبرت الساعات القليلة الماضية. أولاً: شكراً لردكم وتفسيركم واقتراحاتكم - التي ساعدت كثيراً.
لقد اختبرت الإصدار 4 من NSubstitute. إنه يعمل مع رمز المثال أعلاه ، ولكنه لا يحل المشكلة تمامًا في مشاريعنا الواقعية. المشكلة هي أنها تحل مشكلة عدد المكالمات المستلمة الخاطئة فقط لطرق SUT-Calls ، وليس للخصائص.

مثال على كود العمل الخاص بنا الآن:

        [Theory, AutoNSubstituteData]
        public void DoItNow_UsingAutoNSubstitute(
            [Frozen] IRunSpeed runSpeed,
            GetToDaChoppa sut)
        {
            // Arrange
            runSpeed.Speed.Returns(49);

            //Act
            sut.DoItNow();

            //Assert
            var tmp = runSpeed.Received(1).Speed;
            Assert.Equal(1, runSpeed.ReceivedCalls().Count());
        }

ولكن إذا قمت بتغيير الطريقة "GetToDaChoppa.DoItNow ()؛" لتكون خاصية "GetToDaChoppa.DoItNow" فإن ReceivedCallsCount هو +1 مرة أخرى:

        [Theory, AutoNSubstituteData]
        public void DoItNow_UsingAutoNSubstitute(
            [Frozen] IRunSpeed runSpeed,
            GetToDaChoppa sut)
        {
            // Arrange
            runSpeed.Speed.Returns(49);

            //Act
            var x = sut.DoItNow;

            //Assert
            var tmp = runSpeed.Received(1).Speed;
            Assert.Equal(1, runSpeed.ReceivedCalls().Count());
        }

أعتقد أن الأمر يتعلق مرة أخرى بتسمية xUnit حيث نحصل على هذه التسمية لتطبيق طريقة العمل:
image

وتلك الخاصة بتنفيذ الممتلكات غير العاملة:
image

يبدو أن xUnit تستدعي خاصية SUT لاسترداد قيمتها لاستخدامها في اسم الاختبار لكنها لا تفعل ذلك من أجل طرق SUT. كان تفكيري الأول هو أن الأمر يتعلق بالقيمة المعادة لطريقتنا "GetToDaChoppa ()" التي كانت باطلة. ولكن حتى بعد تغييره ليكون "public int GetToDaChoppa ()" ، لا تزال xUnit لا تستدعيها للحصول على قيمة مرتجعة لاسم الاختبار. إنها فقط مشكلة في استخدام الخصائص.

الآن أنا عالق مرة أخرى. أوافق تمامًا على أن هذه ليست مشكلة AutoFixture. لكن في رأيك ، مع معرفة كل الحزم أفضل منا ، ما هو اقتراحك؟

  • فتح قضية لـ NSubstitute؟
  • فتح قضية xUnit2؟
  • أو شيء جديد كليا؟

dklinger شكرا على المتابعة! هل يمكنك من فضلك مشاركة MCVE من الكود للسيناريو الأخير الذي لا يزال يفشل؟ فقط للتأكد من عدم ضياع أي شيء ولم أسيء فهم الظروف.

بعد ذلك سأحاول التحقيق في سبب حدوث ذلك وكيفية التغلب عليه.

شكرا.

نعم بالتأكيد. ها هو:

النظام قيد الاختبار:

    public interface IRunSpeed
    {
        int Speed { get; }
        void Dude();
        int Dude2();
    }

    public class GetToDaChoppa
    {
        private readonly IRunSpeed _runSpeed;

        public GetToDaChoppa(IRunSpeed runSpeed)
        {
            _runSpeed = runSpeed ?? throw new ArgumentNullException(nameof(runSpeed));
        }

        public int DoItNow
        {
            get
            {
                var runningSpeed = _runSpeed.Speed;
                return 0;
            }
        }
    }

حالة اختبار:

        [Theory, AutoNSubstituteData]
        public void DoItNowAsProperty_UsingAutoNSubstitute(
            [Frozen] IRunSpeed runSpeed,
            GetToDaChoppa sut)
        {
            // Arrange
            runSpeed.Speed.Returns(49);

            //Act
            var x = sut.DoItNow;

            //Assert
            var tmp = runSpeed.Received(1).Speed;
            Assert.Equal(1, runSpeed.ReceivedCalls().Count());
        }

أحاول حاليًا متابعة المناقشات على https://github.com/xunit/xunit/issues/1386 و https://github.com/AutoFixture/AutoFixture/issues/805. ربما نفعل شيئًا خاطئًا أو هناك طريقة لإخبار xUnit بعدم إنشاء اسم الاختبار تلقائيًا.
حاولت أيضًا إنشاء TheoryAttribute الخاصة بي التي تتجاوز خاصية DisplayName ولكن هذا لا يساعد أيضًا لأن xUnit لا تزال تستخدم الاسم المُنشأ تلقائيًا داخليًا بطريقة ما. ولكن هذا لمعلوماتك فقط وغير مرتبط تمامًا بالشفرة التجريبية أعلاه.

        public sealed class MyTheoryAttribute : TheoryAttribute
        {
            public MyTheoryAttribute([CallerMemberName] string memberName = null)
            {
                DisplayName = "MyTestCase";
            }
        }

image

مرحبا انا مرة اخرى :)
إنها في الواقع تستدعي xUnit2 جميع خصائص وحقول معلمات طريقة الاختبار التي هي من النوع المركب. سطر الكود هو هذا: https://github.com/xunit/assert.xunit/blob/2b70a9b0c5bb291f98472ec24cec437acf8d65c8/Sdk/ArgumentFormatter.cs#L156

شكرا لدعمك. لقد أعدت فتح مشكلة في xUnit-Repo حيث يجب أن تستمر المناقشة: https://github.com/xunit/xunit/issues/1682

dklinger شكرا على السيناريو المفصل. إنه حقًا صعب للغاية ومن الصعب حله بطريقة ما. من منظور AutoFixture و NSubsitute ، لا يوجد فرق سواء تم استدعاء الكود في مكان ما بعمق داخل xUnit أو في جسم الاختبار.

عادة ، كحل بديل ، يمكنك استخدام ميزة واضحة لـ NSubstitute:

runSpeed.ClearReceivedCalls();

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

إنه لأمر مؤسف أن NSubsitute + xUnit2 + تكامل AutoFixture لا يعمل بشكل جيد ويعاني من هذا النوع من المشكلات. تم تصميم منتج AutoFixture لتبسيط الحياة ، بدلاً من جعلها كابوسًا 😕 نأمل أن ينصحك شباب من xUnit بطريقة سريعة لحل المشكلة للمشروع بأكمله.

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

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات