Sinon: سؤال: خيار عالمي لتطبيق الوعد للاستخدام؟

تم إنشاؤها على ٢ مايو ٢٠١٧  ·  13تعليقات  ·  مصدر: sinonjs/sinon

  • إصدار Sinon: 2.2.0

سؤال:
يقدم Sinon 2.2.0 stub.usingPromise() ، والذي يتيح للمرء استخدام تنفيذ وعد مخصص على أساس كل كعب. هذا رائع ، شكرا على ذلك! 🎉

سؤالي هو: ما رأيك في توفير خيار تكوين عام (على سبيل المثال لكل ملف اختبار) لتحديد تنفيذ وعد مخصص؟

على سبيل المثال ، على غرار ما فعلته sinon-as-promised في الأيام الخوالي: https://github.com/bendrucker/sinon-as-promised#usage

const Bluebird = require('bluebird');
require('sinon-as-promised')(Bluebird);
Feature Request Help wanted major stale

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

قد يكون الخيار الآخر هو كشف وظيفة المصنع على كائن sinon ؛ بمعنى آخر:

const mySinon = sinon.withConfig({ promiseImplementation: Bluebird });

ال 13 كومينتر

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

هذا ما أفكر به: حاليًا sinon Object . ما تقترحه سيؤدي إلى تحول sinon إلى Function يقبل الخيارات Object (دعنا لا نضع أنفسنا في زاوية ونتوقع أن تكون الوسيطة الأولى هي تنفيذ الوعد ).

إذن شيء من هذا القبيل؟

const Bluebird = require('bluebird');
const sinon = require('sinon')({ promiseImplementation: Bluebird});

ماذا تعتقد؟ بينغ @ sinonjs / الأساسية

أعتقد أن فكرة mroderick لتغيير كائن Sinon إلى وظيفة رائعة. من المؤكد أن وجود مكان لتمرير التكوينات إلى مثيل Sinon سيكون مفيدًا في المستقبل ، ليس فقط للتكوين الوعد.

ومع ذلك ، أعتقد أنه يمكن القيام بذلك بطريقة متوافقة مع الإصدارات السابقة من خلال تعيين جميع خصائص كائن Sinon الحالية على الوظيفة. أود الاحتفاظ بالطبيعة "عديمة الجنسية" الحالية وعدم إجبار الجميع على القيام بـ const sinon = require('sinon')() الذي يريد السلوك الحالي. لقد قمنا بهذا بالفعل باستخدام sinon.match ، وهي دالة لها خصائص إضافية مثل sinon.match.string وما إلى ذلك.

قد يكون الخيار الآخر هو كشف وظيفة المصنع على كائن sinon ؛ بمعنى آخر:

const mySinon = sinon.withConfig({ promiseImplementation: Bluebird });

ومع ذلك ، أعتقد أنه يمكن القيام بذلك بطريقة متوافقة مع الإصدارات السابقة من خلال تعيين جميع خصائص كائن Sinon الحالية على الوظيفة. أود الاحتفاظ بالطبيعة "عديمة الجنسية" الحالية وعدم إجبار الجميع على فعل const sinon = يتطلب ('sinon') () الذي يريد السلوك الحالي. لقد فعلنا هذا بالفعل مع sinon.match ، وهي دالة لها خصائص إضافية مثل sinon.match.string وما إلى ذلك.

كان هذا ما كنت أفكر فيه ، لكني فشلت في التعبير عنه.

لمتابعة SemVer ، سنظل بحاجة إلى نشر إصدار MAJOR ، حيث أن الوحدة لا تصدر Object ، بل تصدر Function . لا أرى في هذا عقبة.

أؤيد تغيير التصدير إلى مصنع Function ، بدلاً من إنشاء طريقة مصنع على Object .

ليس لدي أي مشاعر قاسية بشأن أي من الحلين. mroderick أوافق على أن تغيير الكائن إلى وظيفة يعد

@ مانتوني هذا ما أفهمه أيضًا

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

  1. نظرًا لأن هذه خاصية تؤثر على المكتبة بأكملها ، يجب أن تصبح جزءًا من "حالتها" وبالتالي نحتاج إلى توفيرها عند استخدام sinon. ومع ذلك ، فإن الطريقة التي نكشف بها أجزاء Sinon (المجموعات ، والجواسيس ، والأوتار ، وما إلى ذلك) هي من خلال إضافتها إلى الكائن الذي نقوم بتصديره ، ولذا فنحن نوفر لمستخدمينا مجموعة من الطرق التي لا تصل إلى هذه الحالة ، كما ترون في هذا الملف . هذا يجعلنا غير قادرين على تعيين خاصية ببساطة على الكائن الذي نقوم بتصديره: لا تدرك أي من الوظائف المضافة إليه وجود هذا الكائن ، وقد يتسبب ذلك في حدوث مشكلات ويجعل من الصعب قراءة التعليمات البرمجية وتتبع مصدرها. المستقبل عندما يكون لدينا مفاتيح تهيئة أخرى.
  2. يؤدي إنشاء خاصية في العنصر العام المفهرس بواسطة symbol تجنب تضارب مساحة الاسم ويمكننا إتاحة هذا الرمز من خلال defaultConfigs حتى نتمكن من الحصول على أشياء منه متى احتجنا. ومع ذلك ، أعتقد أن هذا النهج ليس هو الأمثل لأنه يفتح إمكانية كبيرة لتسرب الذاكرة (نظرًا لأن جامع القمامة سيبقي دائمًا global[sinonSymbol] على قيد الحياة.
  3. سيكون إنشاء وحدة منفصلة باستخدام تكوينات sinon أمرًا رائعًا ، لأنه نظرًا للطريقة التي يعمل بها require حاليًا (يبحث عن مثيل للملف المطلوب في ذاكرة التخزين المؤقت ويعيده إذا كان موجودًا) يمكننا ببساطة الحصول على نفس حالة التهيئة كلما نطلب sinonConfigs . ومع ذلك ، من أجل تنفيذ ذلك ، أعتقد أن أفضل خيار هو استخدام getConfig ، ولكن يتم إدراجه كـ deprecated عندما يكون لدينا exposeCoreUtils .
    باستخدام getConfig (إعادة تسميته إلى withConfig ) يمكننا ببساطة استبدال الخاصية الافتراضية globalPromise واستخدامها متى أردنا لأن الكائن defaultConfig سيتم تخزينه مؤقتًا وستظل دائمًا كما هي في المستقبل.

أيضًا ، هل نخطط لإعادة مثيل Sinon الجديد عندما نتصل بـ withConfig أم أننا نريد إرجاع نفس المثيل وتغيير تكويناته فقط؟

+1 لهذه الميزة. أواجه بعض المشكلات أثناء محاولة استخدام أحدث إصدارات بلوبيرد + sinon 1 + sinon كما وعدت مع وجود خطأ حول:

TypeError: Cannot set property 'resolves' of undefined
>>   at Object.<anonymous> (/home/lobo/dev/petrocloud/pc3/node_modules/sinon-as-promised/index.js:14:25)

هذا لأن Sinon 2 ليس لديه حلول ، حيث يدعم sinon 2 الوعود المحلية.

نسخ من طلب السحب # 1542 للاحتفاظ بكل شيء في مكان واحد:

فاتسو 83:

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

بالنسبة للبساطة ، لا أرى كل السلبيات السلبية:
const sinon = require('sinon')({promiseImplementation: bluebird})
في كل ملف من ملفات الاختبار تحتاج إلى تغيير هذا. هل أنا مخطئ في ماهية المشكلة؟ أعتقد أنني قد أفعل ذلك ، لأنني لست متأكدًا من أنني حصلت على ما تعنيه بـ "تجاوز ذاكرة التخزين المؤقت المطلوبة". أعتقد أنك قصدت أنك إذا أردت إعادة استخدام نفس الحالة في جميع ملفات الاختبار المختلفة ، فستحتاج إلى اختراق ذاكرة التخزين المؤقت المطلوبة ، ولكن يبدو أن هذا يمثل مشكلة أكثر مما يستحق مقارنة بمجرد تمرير كائن التكوين.

مسكر:

@ fatso83 كلا ، أنت محق. في حالتنا ، نستخدم وعود Bluebird حصريًا (على الرغم من ذلك ، سيتغير ذلك عندما ينتقل async / wait / node 8 إلى LTS في أكتوبر). في إعدادنا السابق قبل الترقية إلى sinon 3 ، كنا نحتاج فقط إلى sinon-as-promised قبل إجراء اختباراتنا ، وكل ما في المستقبل قد استخدم وعود بلوبيرد. أردنا الحفاظ على هذا السلوك لأننا لا نريد أبدًا استخدام الوعود المحلية عن طريق الخطأ.

يمكننا صراحة تنفيذ الوعد في كل ملف اختبار حيث نحتاج إليه ، ولكن هذا سيكون 100٪ من ملفات الاختبار في حالتنا. إذا نسي مطور آخر تمريرها ، فقد يؤدي ذلك إلى سلوك متقطع / تأكيدات سيئة. سيكون من الجيد أن تكون قادرًا على تحديده مرة واحدة فقط لأننا لا نريد أبدًا استخدام الوعود الأصلية.

تحرير: ربما يمكن أن تكون هناك دالة setDefaultConfig تشير بوضوح بالاسم إلى أن لها تأثيرًا عالميًا وأنه لا ينبغي على الأشخاص استخدامها على أساس كل اختبار؟ يبدو أن sinon.addBehavior يمكن أن يعيش هناك أيضًا نظرًا لأنه له تأثير عالمي - على سبيل المثال customStubBehaviors: [ { 'returnsNum': (fake, n) => fake.returns(n) }, ... ]

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

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

ومع ذلك ، من أجل تنفيذ ذلك ، أعتقد أن أفضل خيار هو استخدام getConfig الحالي ، ولكن يتم إدراجه على أنه مهمل عندما نكشف CoreUtils.

لم يتم إهمال getConfig . إنها فقط الدالة _exported_ التي تم إهمالها من _public API_. من الجيد تمامًا الاستمرار في إعادة استخدامه داخليًا. نحن فقط لا نريد أن تعتمد الإرادات الخارجية على سلوكها.

أيضًا ، هل نخطط لإعادة مثيل Sinon الجديد عندما نتصل بـ withConfig أم أننا نريد إرجاع نفس المثيل وتغيير تكويناته فقط؟

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

شيء آخر ، هو أنه من المناقشة أعلاه ، أعتقد أننا وصلنا إلى جعل المصنع sinon ، بدلاً من إضافة طريقة المصنع ، لذا withConfig خارج الباب: smile_cat: كما Phred sayd in ناقشت المجموعة على تويتر:

يجب أن يكون لدى require('sinon') نفس واجهة برمجة التطبيقات والخصائص مثل require('sinon')(config) .

ملاحظة: قد نفكر في نقل المناقشة إلى قضية منفصلة ، حيث يتعامل هذا مع شيء مختلف تمامًا ، على الرغم من اعتماده على التغيير الذي تمت مناقشته.

mroderick فيما يتعلق بالمصنع الذي سيتم إرفاقه بالكائن sinon للحصول على مثيل تم تكوينه بدلاً من الكائن المتاح حاليًا ، أعتقد أنه يجب القيام به بشكل مشابه لتسمية وضع الحماية.

لذلك أنا فقط سأستخدم

const mySinon = sinon.create(config);

يعد هذا أكثر سهولة من إدخال اسم وظيفة مصنع مختلف هنا.

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

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