Sinon: لا يعمل التجسس "returnValue" مع المولدات

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

عند العمل مع وظائف المولد ، تكون قيمة إرجاع الجاسوس دائمًا undefined . إليك حالة اختبار فاشل:

require('should');

var sinon = require('sinon');
var co = require('co');

var foo = {
  bar: function() {
    return 'bar';
  },
  biz: function *() {
    return 'biz';
  }
}

describe('Return value', function() {
  it('should work with regular functions', function() {
    sinon.spy(foo, 'bar');

    foo.bar();

    foo.bar.firstCall.returnValue.should.equal('bar');
  });

  it('should work with generator functions', co.wrap(function*() {
    sinon.spy(foo, 'biz');

    var result = yield foo.biz();

    result.should.equal('biz');
    foo.biz.firstCall.returnValue.should.equal('biz');
  }));
});

تشغيل باستخدام npm install co mocha should sinon && ./node_modules/.bin/mocha --harmony index.js .

2.x Unverified

ال 20 كومينتر

لا يدعم Sinon ميزات ES6 حتى الآن. لم يبدأ العمل على هذا بعد ، لذا لا أعرف متى سينجح ذلك.

mantoni ، صحيح ، كان هذا أكثر من طلب ميزة :) هل تريد تركه مفتوحًا ، على سبيل المثال ، مع نوع من العلامات ("es6"؟) بحيث يكون من الأسهل إعادة - تقييم ما يجب القيام به؟

ستكون هذه ميزة رائعة.

ruimarinho لقد وجدت هذا https://github.com/ingameio/SinonES6.JS
يبدو أن استبدال طلب ("sinon") بمتطلب ("sinon-es6") يجعل اختباراتك تنجح

-
تحرير بواسطة @ fatso83 في 22 يونيو 2017:
هذا لا يبدو أن يكون صحيحا. لقد اختبرت هذا يدويًا. إنه يفشل على الإطلاق ، وهو أمر منطقي تمامًا لأن sinon-es6 _ فقط ينفذ دعمه للمولدات للسخرية _.

هل هناك من يعمل على ذلك؟

emgeee لا أعرفه.

سيكون إجراء + 1ruimarinho sinon.js مع ميزات es6 أمرًا رائعًا!

ingameio هل ترغب في إجراء علاقات عامة مع تغييراتك؟

@ fatso83 شكرا على الاقتراح!
سأفعل العلاقات العامة قريبًا ؛)

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

gaguirre هذه أخبار رائعة. قام Maximillian للتو بتحويل جميع الاختبارات إلى Mocha ، وأجرى بعض التغييرات في إعداد الاختبار أثناء ذلك ، لذلك ربما تنجح الأمور إذا قمت بسحب أحدث التغييرات من master ؟

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

@ fatso83 لقد دفعت الإصدار الأول إلى undercope / sinon .
تحدث المشكلة الرئيسية عند تشغيل الاختبارات بمحرك لا يدعم es6 (phantomjs في هذه الحالة): يفشل عند تحليل الكود ، لذا فأنا أستخدم eval() كحل مؤقت حيث يمكن أن تكون محاطًا بتجربة / قبض على. أعتقد أن هذا غير مقبول لكنها نقطة انطلاق.

في الوقت الحالي ، أحاول التفاف استدعاء المولد في ملف آخر وأطلبه ديناميكيًا ، لكنه لا يعمل ، أعتقد أن المتصفح يقوم بتجميع حتى الملفات المطلوبة ديناميكيًا. أتساءل عما إذا كان من الممكن استبعاد بعض الملفات عند تشغيل npm run test-headless .

ما رأيك يمكن أن يكون أفضل حل؟

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

مجرد تفويض الشيك الفعلي بسيط مثل if(require('generator-support')){ ... } ، لكن هذا لا يصلح مشكلة التحليل الفعلية.

أي أفكار حول كيفية التعامل مع هذا ، mantoni وmroderick؟

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

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

اقتراح :

استخرج كود المولد في ملف منفصل و require() هذا الملف عند الطلب فقط عند تغليف وظيفة المولد ، على سبيل المثال:

؟ /es6-support.js:

"use strict";

exports.getGeneratorWrapper = function(method, ctx, args) {
    return function* () {
        return mockObject.invokeMethod(method, ctx, args);
    }
}

يتوقع lib / sinon / mock.js-> ...:

var wrapper = function () {
    return mockObject.invokeMethod(method, this, arguments);
});

if (/^function\s*\*/.test(method.toString())) {
    wrapper = require('es6-support').getGeneratorWrapper(method, this, arguments);
}

wrapMethod(this.object, method, wrapper);

(قم أيضًا بعمل مماثل مع اختبارات الوحدة ، وتأكد من أن تتبع تغطية الشفرة لا يتسبب في تضمين ملف "es6-support" تلقائيًا.)

اقتراح بديل :

هل سيظل التوافق مع ES5 هدفًا ذا قيمة بحلول الوقت الذي يصبح فيه sinon 2.0 جاهزًا للإصدار؟ ربما حان الوقت لإخبار الأشخاص القلائل الذين ما زالوا يدعمون البيئات القديمة الخاصة بـ ES5 فقط بدون مستخدم أجهزة الإرسال والاستقبال أنه سيتم تركهم في 1.x.

@ evan-king هذا المطلب الشرطي ليس حلاً ، لأنه سيؤدي إلى كسر في تصميمات المتصفح. نظرًا لأن الشرطي يتطلب هزيمة التحليل الثابت للرسم البياني للتبعية ، فلن تتمكن أدوات مثل WebPack و Rollup و Browserify من التعامل معه. إما أنها داخل أو خارج تماما.

ونعم ، توافق ES5 شيء. دعم مولد ES6 رديء في أحسن الأحوال ، وإجبار الأشخاص على استخدام أدوات إضافية لاستخدام Sinon في مشاريعهم سيؤدي إلى رفع مستوى إجراء الاختبار. وبالنسبة للكثيرين ، فإن هذه العتبة مرتفعة بما يكفي كما هي. القدرة على تضمين علامة نصية بسيطة لتشغيلها هي ميزة مهمة IMHO. قد نكسر توافق ES5 في وقت ما ، لكنه ليس على خارطة الطريق الخاصة بنا ولم تتم مناقشته حتى مع Sinon 3. لقد تم إيقاف تشغيل Sinon 2 منذ بعض الوقت ؛ هناك بعض المضايقات البسيطة التي تمنعنا من إصدار بيان رسمي.

هناك طريقتان أساسيتان للحصول على توافق ES6 دون كسر توافق وقت تشغيل ES5 الحالي الذي يمكنني التوصل إليه ، ولست متأكدًا من الطريقة الأخيرة (لم أختبرها):

التقييم المشروط للوحدات

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

بافتراض وجود شيء مثل brfs ، سيبدو الرمز مشابهًا لما يلي:

_runtime-features.js_

var features = {};
try { 
    new Function("var foo = function* foo(){ }") ;
    features.generatorSupport = true; 
} 
catch(err){ features.generatorSupport = false; }
module.exports = features;

_es6-generator-wrapper.js_

return function* () {
    return mockObject.invokeMethod(method, ctx, args);
}

_es6.js_

var features = require('./runtime-features');

if( features.generatorSupport ) {
    var code = fs.readFileSync('./es6-generator-wrapper.js');
    module.exports.getGeneratorWrapper = new Function("mockObject", "method", "ctx", "args", code);
} else {
    module.exports.getGeneratorWrapper = function() { throw new TypeError("You tried using a generator function in a runtime only capable of running ES5 code"); }
}

تخليد سينون

هذا هو الشيء الذي لست متأكدًا منه لأنني لم أحاول فعلاً. إذا قمنا بتحويل البنية من خلال Babel إلى ES5 ، فيمكننا كتابة كود ES6 في كل مكان ، وتجنب القفز عبر الأطواق كما فعلت أعلاه ، ولا يزال بإمكاننا استخدام نفس أنواع الفحوصات للمولدات. سيتم تنفيذها فقط باستخدام بنيات ES5. بالطبع ، سيظل اختبار ES6 في متصفحات ES5 يفشل. هذا له نفس الاتجاه الصعودي السابق من جانب العميل ، لكننا قد نعيق المساهمات مثل معرفة ES2015 بأشياء مثل yield ، async ، function*() بعيدة عن الوصول جمهور عريض.

+1

rpavlovs ، لا جدوى من إضافة +1 إلى الموضوع. تحتوي واجهة مستخدم GitHub على زر "إضافة رد فعل" أعلى كل تعليق إذا كنت بحاجة إلى التعبير عن مشاعرك. +1 لن تفعل شيئًا. من ناحية أخرى ، فإن طلب السحب الذي ينفذ أحد الاقتراحات أعلاه (أو شيء أكثر ذكاءً) لديه فرصة أفضل بكثير لإصلاح هذه المشكلة 😄

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

لبدء تجسيد ذلك ، قمت بإنشاء فرع جديد يحمل تعديلات ingameio على mock api ، بينما في نفس الوقت لا يكسر توافق ES5 (باستخدام الاختراق المذكور أعلاه).

ما يزعجني قليلاً هو أنني لا أستطيع حقًا معرفة كيفية اختبار التغييرات الأصلية بواسطة Ingameio ، حيث لا يعمل أي من أمثلة الاختبار - ولا حتى المثال الموجود في الشوكة مكتمل ، ولا يمكنني الحصول على أشياء لكسرها قبل / بعد التغييرات.

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

إنني أدرك بالفعل أن الأمثلة باستخدام co ربما تستخدمه فقط لتكون قادرًا على استخدام yield مباشرة في اختبار Mocha ، لكن فقط قم بلف المثال الخاص بك في IIFE أو بطريقة أخرى لتحقيق الشيء نفسه من أجل من أجل المزيد من الوضوح.

هذا اختبار بسيط لكيفية دعم المولدات (يعمل في Sinon اليوم):

require("should");

var sinon = require("../sinon");

var foo = {
    bar: function () {
        return "bar";
    },
    biz: function *() {
        return "biz";
    }
};

describe("generator support", function () {
    it('should work with generator functions',  function(){
        var spy = sinon.spy(foo, 'biz');

        var iterator = foo.biz();
        var result = iterator.next();

        result.value.should.equal('biz');
        result.done.should.equal(true);
        spy.firstCall.returnValue.should.be.an.Object();
        spy.firstCall.returnValue.next.should.be.a.Function();
    });
});

الآن ، ما هي ملحقات API التي نريدها؟
من الاختبار الأصلي ، أفترض أننا نود أن نرى شيئًا مثل

foo.biz.firstGeneratedValue.should.equal('biz');
أو
foo.biz.generatedValue[0].should.equal('biz');
؟

سي سيruimarinho

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

يرجى الانضمام إلى المناقشة حول كيفية ظهور API للتعامل مع المولدات (والمكررات المرتبطة بها) في الإصدار رقم 1467

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