Sinon: فشل الاختبار بشكل غير متوقع بعد إصدار v7.2.0

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

صف الخلل
تؤدي ترقية Sinon إلى أحدث إصدار v7 إلى حدوث بعض الإخفاقات غير المتوقعة. كان التغيير الوحيد ذي الصلة الذي تمكنت من تحديده هو PR هذا: # 1955 - استبدال deep-equal.js بـ samsam.deepEqual .
اجتازت الاختبارات جميع الإصدارات حتى 7.2.0 ، والعودة إلى 7.1.1 (إصدار واحد للخلف) لا تسبب أي مشاكل وتم اجتياز جميع الاختبارات.

لوحظ خطأ:

AssertionError: expected addTracks to have been called with arguments [{ language: "en", trackContentType: "CEA608" }]
[[functionStub] { language: "en", trackContentType: "CEA608" }] [{ language: "en", trackContentType: "CEA608" }]

اختبار إنتاج الخطأ:

    it('should call getTextTracksManager, Track, and setCaptionLang', () => {
      sinonSandbox.stub(chromecastReceiver, 'setCaptionLang');
      chromecastReceiver.player.getTextTracksManager = sinonSandbox.stub()
        .returns({ addTracks: sinonSandbox.spy() });
      sinonSandbox.stub(cast.framework.messages, 'Track').returns(() => ({}));

      chromecastReceiver.loadCaptions('off');

      expect(chromecastReceiver.player.getTextTracksManager).to.have.callCount(1);
      expect(cast.framework.messages.Track).to.have.been
        .calledWith(3, cast.framework.messages.TrackType.TEXT);
      expect(chromecastReceiver.textTracksManager.addTracks).to.have.been.calledWith([{
        trackContentType: cast.framework.messages.CaptionMimeType.CEA608,
        language: 'en',
      }]);
      expect(chromecastReceiver.setCaptionLang).to.have.been.calledWith('off');
    });

لإعادة إنتاج
خطوات إعادة إنتاج السلوك:

  1. استخدم أي إصدار من Sinon أعلى من 7.1.1
  2. إجراء اختبار العينة (أعلاه)
  3. انظر الخطأ

سلوك متوقع
يجب أن يجتاز الاختبار

لقطات
إذا أمكن ، أضف لقطات شاشة للمساعدة في شرح مشكلتك.

السياق (يرجى استكمال المعلومات التالية):

  • إصدار المكتبة: 7.2.0+
  • البيئة: macOS 10.14.5

يرجى إعلامي إذا كان بإمكاني تقديم مزيد من المعلومات حول هذا الأمر.

Bug Regression pinned

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

مرحبا @ fatso83 ،

شكرا لأخذ وقتك للنظر فيه. لقد فعلت كما طلبت مني وأنشأت عرضًا توضيحيًا لـ Runkit يُظهر الخطأ. ما عليك سوى التعليق / إلغاء التعليق على عبارات require('sinon') المختلفة وتشغيل الكود لمعرفة الخطأ.

https://runkit.com/danielkg/sinon-issue-reproducible-bug-template

أقوم بنشر الكود هنا أيضًا في حالة عدم عمل runkit لأي سبب من الأسباب.

// Employs 'mini-mocha' to emulate running in the Mocha test runner (mochajs.org)
require("@fatso83/mini-mocha").install();
// const sinon = require('[email protected]'); // WORKS!
const sinon = require('[email protected]'); // FAILS!
// const sinon = require('sinon');       // FAILS!
const { assert } = require('@sinonjs/referee');

const SAMPLE_USER = {
    id: 1,
    name: 'Kid',
    age: 22,
    weight: 83.5,
    notes: [{ txt: 'abc' }, { txt: 'def' }, { txt: 'ghi' }],
};

class MyUser {
    constructor(id, name, age, weight, notes = []) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.notes = notes;
    }
}

const createFakeUser = overrides => ({
    id: '007',
    name: 'Bond',
    ...overrides,
});

class Talkie {
    talk(user, topic) {
        console.log('talked to', user.name, 'about', topic);
    }
}

const action = (userId, talkie) => {
    const { name, age, weight, notes } = SAMPLE_USER;
    const user = new MyUser(userId, name, age, weight, notes);

    talkie.talk(user, 'apples');

    return user;
}


describe('stubbing', () => {
    const talkie = new Talkie();

    afterEach(() => {
        sinon.restore();
    });

    beforeEach(() => {
        sinon.spy(talkie, 'talk');
    });

    it('is the same user', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        assert.equals(JSON.stringify(userA), JSON.stringify(userB));
    });

    it('should set the return value', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        sinon.assert.calledWith(talkie.talk, userB, sinon.match.string);
    });
});

يرجى إلقاء نظرة أخرى عندما يكون لديك الوقت. شكرا لك.

أطيب التحيات،
دانيال

ال 11 كومينتر

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

هل يمكنك عمل مرشح أدنى للتكاثر؟ ليس عليك نسخ المثال الأصلي بالكامل ، مثل التبسيط مثل var myObject = { aMethod: function(){}, aProp: 42 }; // etc .

إذا كنا نعلم أن هذا كسر ، فسنقوم بالطبع بزيادة الإصدار الرئيسي ، لذلك سيكون اختبار الانحدار رائعًا!

يبدو أن PS يبدو أن sinon-chai تشارك أيضًا. هذا يستحق الإدراج.

@ fatso83 دعني أرى كيف يمكنني الحصول على مثال معزول

أي تحديثات؟

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

mantoni ألم تبلغ عن حدوث شيء كهذا في أحد مشاريعك؟

آسف لقلة التحديثات ، لم أعد مرتبطًا بالمشروع الذي احتوى على المشكلة. إذا كان أي شخص آخر يعاني من نفس المشكلة ، فسيكون من الرائع أن يقدم مثالاً على repro

@ fatso83 لا أذكر

إغلاق كما لا يمكن إعادة إنتاج

آسف لإحياء هذه المشكلة من الموت ، لكنني أواجه نفس المشكلة.

_تم تبسيط الكود أدناه لأغراض التوضيح.

في طلبي لدي هذا الفصل

class MyUser {
  // ... some user properties  
}

وأستخدمها لاحقًا في وظيفة تحكم Koa مثل هذه

const mqClient = require('./mqClient');

// GET /userDetails/<id> endpoint
async function getUserDetailsController(req, res) {
  const user = new MyUser();

  // populate user with properties etc.
  user.id = '1';
  user.name = 'Hans Gruber';
  user.tasks = [{ id: '42', title: 'execute Nakatomi tower heist' }];

  // ... get more details ...

  // Notify other users about this user
  mqClient.notifyOthers(user);

  res.json({ ok: true, user });
}

وفي getUserDetailsController.test.js أفعل شيئًا كالتالي:

const mqClient = require('./mqClient');

const createExpectedUser = overrides => {
  id: '1',
  name: 'Hans Gruber',
  tasks: [{ id: '42', title: 'execute Nakatomi tower heist' }],
  ...overrides
};

it('does not fail', async () => {
  sinon.spy(mqClient, 'notifyOthers');

  const expectedUser = createExpectedUser();

  await presetRequest // helper object to run the controller code
    .get('/userDetails/1')
    .expect(200);

  // This works with sinon 7.1.1.
  // This fails with sinon 7.2.0 and onwards.
  sinon.assert.calledWithMatch(mqClient.notifyOthers, expectedUser);
});

لقد اختبرت هذا مع sinon 7.1.1 (الذي يستخدم "2.1.3" من samsam ) ، وهذا يعمل.
فشل الإصدار 7.2.0 (يستخدم 3.3.3 من samsam ).
أحدث إصدار 9.2.3 فشل أيضًا (يستخدم 5.3.0 من samsam ).

أنا على Node 14.5.3 ، ولكن هذا يحدث أيضًا على Node 12.20.0.

لقد قارنت user في وحدة التحكم و expectedUser في الاختبار عبر JSON.stringify يدويًا وهم متساوون بنسبة 100٪. الاختلاف الوحيد من الناحية التركيبية هو أن وحدة التحكم تستخدم الفئة ، بينما يستخدم الاختبار كائنًا حرفيًا.

هل لدى أي شخص فكرة جيدة لماذا يحدث هذا؟ أو هل لدى أي شخص فكرة جيدة عن كيفية التغلب على هذا؟

أطيب التحيات،
دانيال

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

أنا أحب إصلاح الأخطاء ، ومع ذلك ، إذا كان بإمكانك قضاء بعض الوقت في محاولة صنع شيء ما _ يمكنني تشغيله_ ، فافعل ذلك! RunKit هي خدمة رائعة للقيام بذلك: https://runkit.com/fatso83/sinon-issue-reproducible-bug-template

مرحبا @ fatso83 ،

شكرا لأخذ وقتك للنظر فيه. لقد فعلت كما طلبت مني وأنشأت عرضًا توضيحيًا لـ Runkit يُظهر الخطأ. ما عليك سوى التعليق / إلغاء التعليق على عبارات require('sinon') المختلفة وتشغيل الكود لمعرفة الخطأ.

https://runkit.com/danielkg/sinon-issue-reproducible-bug-template

أقوم بنشر الكود هنا أيضًا في حالة عدم عمل runkit لأي سبب من الأسباب.

// Employs 'mini-mocha' to emulate running in the Mocha test runner (mochajs.org)
require("@fatso83/mini-mocha").install();
// const sinon = require('[email protected]'); // WORKS!
const sinon = require('[email protected]'); // FAILS!
// const sinon = require('sinon');       // FAILS!
const { assert } = require('@sinonjs/referee');

const SAMPLE_USER = {
    id: 1,
    name: 'Kid',
    age: 22,
    weight: 83.5,
    notes: [{ txt: 'abc' }, { txt: 'def' }, { txt: 'ghi' }],
};

class MyUser {
    constructor(id, name, age, weight, notes = []) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.notes = notes;
    }
}

const createFakeUser = overrides => ({
    id: '007',
    name: 'Bond',
    ...overrides,
});

class Talkie {
    talk(user, topic) {
        console.log('talked to', user.name, 'about', topic);
    }
}

const action = (userId, talkie) => {
    const { name, age, weight, notes } = SAMPLE_USER;
    const user = new MyUser(userId, name, age, weight, notes);

    talkie.talk(user, 'apples');

    return user;
}


describe('stubbing', () => {
    const talkie = new Talkie();

    afterEach(() => {
        sinon.restore();
    });

    beforeEach(() => {
        sinon.spy(talkie, 'talk');
    });

    it('is the same user', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        assert.equals(JSON.stringify(userA), JSON.stringify(userB));
    });

    it('should set the return value', () => {
        const userA = action(1, talkie);
        const userB = createFakeUser(SAMPLE_USER);

        sinon.assert.calledWith(talkie.talk, userB, sinon.match.string);
    });
});

يرجى إلقاء نظرة أخرى عندما يكون لديك الوقت. شكرا لك.

أطيب التحيات،
دانيال

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