Sinon: يطرح وضع الحماية خطأ "يتعذر إيقاف خاصية خاصة غير موجودة"

تم إنشاؤها على ١٨ أغسطس ٢٠١٧  ·  14تعليقات  ·  مصدر: sinonjs/sinon

لقد حاولت للتو الترقية من 2.4.1 إلى 3.2.1 وواجهت المشكلة التالية. يعمل هذا الرمز في 2.4.1:

        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });

ولكن في 3.2.1 يطرح استثناء: TypeError: Cannot stub non-existent own property google

لم يتم ذكره في دليل الترحيل لذا يبدو أنه انحدار.

Bug Regression

التعليق الأكثر فائدة

~ شكرا لاستعادة هذا السلوك. ~

أراد إضافة حالة استخدام تدعم خاصية stubbing غير موجودة.

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

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) طريقة واضحة جدًا للتعبير عن ذلك. من الجيد أن أحصل على نفس السلوك ، - على الرغم من أنني لا أعرف في وقت التشغيل ما إذا كان المفتاح مضبوطًا أم لا.

ال 14 كومينتر

ذات صلة بـ # 1512.

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

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

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

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

كما أنني لاحظت أنني ارتكبت خطيئة عدم تقديم مثال كامل. يتم إنشاء وضع الحماية الخاص بي بتنسيق 2.4.1:

let sandbox;

before(() => { sandbox = sinon.sandbox.create(); })
afterEach(() => { sandbox.restore(); })

لست متأكدًا مما إذا كان هذا مهمًا ؛ نأسف لعدم تقديمه عاجلاً.

أعتقد أنه في السيناريوهات مثل تلك التي يصفها ZebraFlesh ، أفضل أن تكون تركيبات النص أكثر وضوحًا.

// not so explicit, doesn't work with [email protected]
beforeEach(function() {
    const spy = sandbox.spy();
    sandbox.stub(window, 'google').value({
        maps: {
            LatLng: x => x,
            Map: spy
        }
    }); 
});
// more explicit, works with sinon<strong i="9">@2</strong>, sinon<strong i="10">@3</strong>
function setGoogleMapsFixture(sandbox) {
    window.google = {
        maps: {
            LatLng: x => x,
            Map: sandbox.spy()
        }
    };
}

function removeGoogleMapsFixture() {
    delete window.google;
}

beforeEach(function() {
    setGoogleMapsFixture(sandbox)
});

// not using afterEach, as this only needs to happen
// after the last test in this block is run
after(function() {
    removeGoogleMapsFixture();
});

مع إعداد أكثر وضوحًا للتثبيت كما هو موضح أعلاه ، لا تحتاج إلى ميزة في Sinon تسمح بإيقاف الخصائص الخاصة غير الموجودة.

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

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

أعتقد أن إيقاف الممتلكات الخاصة غير الموجودة يجب أن يظل غير مدعوم. يجب علينا تحديث الوثائق.

mroderick أنا أتفق معك في أنه قد يؤدي إلى تقليل الأخطاء ، لكننا نؤيد هذا بالفعل

ذلك إما:

  • قم بإزالة الاختيار على الفور لصناديق الحماية لإصلاح هذه الميزة الفاصلة

او و(؟)

  • قم بإزالة الوظيفة لكل من الأجزاء الجذرية العادية وذات آلية تحديد الوصول

    • إصدار إصدار رئيسي جديد مع مستندات محدثة

مع إعداد أكثر وضوحًا للتثبيت كما هو موضح أعلاه ، لا تحتاج إلى ميزة في Sinon تسمح بإيقاف الخصائص الخاصة غير الموجودة.

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

it('handles the success case', () => {
        const spy = sandbox.spy();
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: spy
            }
        });
        // ... test, including asserting that the spy was called
});

it('handles the failure case', () => {
        const msg = 'test error';
        sandbox.stub(window, 'google').value({
            maps: {
                LatLng: x => x,
                Map: sandbox.stub().throws(new Error(msg))
            }
        });
        // ... test, ignoring spy calls and instead focusing on error handling
});

يتميز السلوك في 2.x بأنه يتم تنظيف كل شيء بشكل صحيح بعد كل اختبار عبر sandbox.restore() . باستخدام مثال إعداد التركيبات الأكثر وضوحًا الموضح أعلاه ، أفترض أنه يمكنك حذف الخاصية غير الخاصة في خطاف afterEach لتحقيق نفس التأثير.

لحل مشكلة إدخال أخطاء محتملة عن طريق كتابة اسم خاصية موجودة عن غير قصد ، يمكن لـ sinon تعديل واجهة برمجة التطبيقات العامة:

  • stub.ownValue() : كعب روتين للخصائص الخاصة فقط ، ورمي للخصائص غير الخاصة
  • stub.value() : كعب رقيق فقط للخصائص غير الخاصة ، رميات للخصائص الخاصة

تصبح واجهة برمجة التطبيقات أكثر وضوحًا ويضطر المستهلك إلى اختيار الأداة المناسبة للمهمة المطروحة.

يرتبط هذا ارتباطًا وثيقًا بالمناقشة في # 1508 (على الرغم من أنه يتعامل مع بذرة عادية) h ، حيث يمتلك lucasfcosta وجهة نظر معارضة - يجب ألا نرميها مقابل خصائص undefined . أيا كان ما ننتقل إليه ، فأنا أؤمن بشدة بأننا بحاجة إلى أن نكون متسقين في واجهات برمجة التطبيقات (APIs) القوية للأوتار العادية وصناديق الحماية. لا يجب أن نؤيده في حالة واحدة دون الأخرى.

الوضع الآن هو:

  • تستخدم بذرة عادية لإلقاء 1.x ، لكن هذا تغير في 2.0 ولم يعد يرمي الآن بعد الآن
  • لم تستخدم صناديق الرمل للرمي ، لكنها بدأت في الرمي 3.1 (؟)

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

على الرغم من أنني أتفهم الإزعاج ، يبدو أن هناك حلًا سهلًا مع الحد الأدنى من التغييرات في التعليمات البرمجية.

before(function() {
  window.google = 'This is a placeholder for sinon to overwrite.';
});

after(function() {
  delete window.google;
});

هذا يسمح لكود sinon بالبقاء دون تغيير.

التراجع مقابل التوثيق الضعيف

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

fearphage إن الحفاظ على الوضع الراهن يعني أن إيقاف الحقول غير الموجودة هو سلوك غير مدعوم لصناديق الحماية ، في حين أنه سلوك مدعوم للعذرات العادية. أليس من المؤسف بعض الشيء أن مجموعتي الميزات لا تتوافق؟

تم تنفيذ القرار في # 1557

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

أحصل على أن Typescript ربما لا تكون أولوية بالنسبة لكم يا رفاق ، ولكن حتى في JS يبدو بديهيًا أن myObject.callMe() سيتم تنفيذه بسعادة تامة ، بينما لن يتم تنفيذ sinon.stub(myObject, "callMe") في هذه الحالة. أفضل عدم الاضطرار إلى الذهاب والتحقيق في كيفية وضع هذا الكائن المحدد معًا حتى أعرف كيفية إيقافه.

أعتقد حقًا أن هذه حالة استخدام مهمة لإنشاء مسار سعيد ، مع الأخذ في الاعتبار أن الفصول تحصل على المزيد من الدعم المحلي في JS.

إذا تلقيت خطأ يفيد بأن الطريقة غير محددة على الكائن ، فأنت تعلم أن الخطأ ربما يكون في النموذج الأولي. ثم لا يبدو تعديل الكائن مباشرة باستخدام myObject.callMe = sinon.stub(); مثل هذا القدر من المتاعب IMHO ... يجب أن يوفر لك أيضًا من إنشاء وظائف تنظيف / تفكيك ، حيث لم يتم تغيير النموذج الأولي أبدًا.

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

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

~ شكرا لاستعادة هذا السلوك. ~

أراد إضافة حالة استخدام تدعم خاصية stubbing غير موجودة.

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

sandbox.stub(serverSecrets, 'the_key_i_need_set').value(fakeValue) طريقة واضحة جدًا للتعبير عن ذلك. من الجيد أن أحصل على نفس السلوك ، - على الرغم من أنني لا أعرف في وقت التشغيل ما إذا كان المفتاح مضبوطًا أم لا.

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