Mocha: فشل اختبار عدم التزامن مع انتهاء المهلة بدلاً من خطأ التأكيد

تم إنشاؤها على ٥ فبراير ٢٠١٤  ·  25تعليقات  ·  مصدر: mochajs/mocha

هذا الاختبار:

    it('returns the correct value', function(done) {
      var returnValue = 5;

      aPromise.then(function() {
        expect(returnValue).to.equal(42);
        done();
      });

    });

فشل هذا الاختبار مع timeout of 2000ms exceeded بدلاً من خطأ التأكيد. أعتقد أن هذا يرجع إلى أن المكالمة expect() تسبب في حدوث خطأ ، ولم يتم تنفيذ done() أبدًا ، وأنا أتساءل عما إذا كانت هناك طريقة أفضل لاختبار هذا النوع من الكود.

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

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

it('returns the correct value', function() {
    var returnValue = 5;

    return aPromise.then(function() {
        expect(returnValue).to.equal(42);
    });
});

ال 25 كومينتر

هل تم حل aPromise الإطلاق؟ إذا لم يكن الأمر كذلك ، فلن يكون هناك خيار كبير سوى التخلي عن مهلة.

NickHeiner نعم ، تقرر ؛ ثم يجد expect() أن returnValue ليس equal(42) ويلقي.

gurdiga كيف تعرف أنه يرمي إذا حصلت على مهلة وليس خطأ تأكيد؟

hallasNickHeiner هنا هو الشيء تشغيل: http://jsfiddle.net/gurdiga/p9vmj/.

gurdiga يبدو لي أن خطأه الخاص. حاول إضافة .catch(done) إلى وعدك وأعتقد أنه سيعمل على النحو المنشود.

hallas نجاح باهر: _that_ كان الجواب! :) يبدو أن aPromise.finally() هو الخيار الأمثل لوضع done فيه: يجب أيضًا استدعاؤه عند الوفاء بالوعد. ؛)

شكرا لك!

أشعر بالغباء.

أعتقد أنني حصلت عليه أخيرًا: عندما يتم طرح أي شيء في أي من وظائف معالج الوعد ، سواء كان ذلك الذي تم تمريره إلى .then() ، إلى .catch() أو إلى .finally() ، يكون الخطأ هو تم التعامل معها من خلال مكتبة الوعد. بهذه الطريقة ، لا يرى عداء الاختبار الخطأ الحقيقي أبدًا ، ولا يتم استدعاء done() أبدًا (لأن شيئًا قبل طرح خطأ تأكيد) ، وبالتالي فإن خطأ المهلة هو كل ما تحصل عليه من عداء الاختبار.

للتخلص من الوعد ، أستخدم setTimeout() :

    it('returns the correct value', function(done) {
      var returnValue = 5;

      aPromise.then(function() {
        setTimeout(function() {
          expect(returnValue).to.equal(42);
          done();
        });
      });
    });

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

مع تمرير done إلى .catch() أو .finally() يعتبر الاختبار ناجحًا في أي حال ، لذلك إذا كانت هناك أخطاء في التأكيد ، فلن تراها أبدًا.

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

it('returns the correct value', function() {
    var returnValue = 5;

    return aPromise.then(function() {
        expect(returnValue).to.equal(42);
    });
});

أعتقد أن هذه القضية لا تزال قائمة. لدي مشكلة انتهاء مهلة لا يمكن حلها من خلال إعادة وعد لأن الوحدة الخاصة بي لا تستخدم الوعود.

it("works", function(done) {
    new Something()
    .on("eventA", function(result) {
        expect(result).to.be.true;
    })
    .on("eventB", function(result) {
        expect(result).to.be.false;
        done();
    });
});
  • يبدو أن التفاف المثيل في Promise مبالغ فيه.
  • إن تغليف كل تأكيد في try / catch يبدو أيضًا مفرطًا ، والأهم من ذلك أنه ينتج عنه Error: done() called multiple times .

الأفكار:
http://staxmanade.com/2015/11/testing-asyncronous-code-with-mochajs-and-es7-async-await/

فيما يتعلق بتوصيات منشور المدونة ، لا أعرف شيئًا عن معالجة أخطاء الوظيفة غير المتزامنة ، ولكن بالنسبة للوعود الواضحة ، فإن توصية try-catch غريبة: محاولة الوعد الأصلية بدون محاولة التقاط كانت صحيحة تقريبًا ، فقد احتاجت فقط إلى استخدام .catch(done) بدلاً من استخدام المعلمة الثانية لـ then كـ done . (صحيح ، نظرًا لأن Mocha لديها دعم مباشر للوعود ، يمكنك أيضًا إرجاع الوعد ، ولكن لما يستحق ...) لم تكن المشكلة في مثال الوعد الأولي عدم وجود try-catch ، بل كان ذلك المعالج الثاني إلى then لا يُستدعى مع استثناءات طرحها المعالج الأول ، بينما التالي catch هو ؛ لا أعرف ما هو الأساس المنطقي لتصميم الوعود بهذه الطريقة ، لكن هذا هو مدى الوعود. بالإضافة إلى ذلك ، إذا كان هناك العديد من then s لسبب ما ، فستكون هناك حاجة إلى .catch(done) نهائي واحد فقط ، وهي نقطة تفوق على المحاولة داخل المعالجات (فوق حقيقة أن .catch(done) أقل معيارية لتبدأ).

بالنسبة لواجهة برمجة التطبيقات الخاصة بك:

  1. هل أنت متأكد من أنه تم استدعاء كلا الحدثين ، وبالترتيب الصحيح؟ إذا لم تكن كذلك ، فكيف سيحول اختبارك ذلك إلى فشل عادي؟
  2. ما الذي يحدث عادةً للاستثناءات التي يتم طرحها من معالجي الأحداث؟ إذا لم ينتشروا بالطريقة التي يعملون بها في الكود المتزامن وبدلاً من ذلك من المفترض أن يتم الاستماع إليهم على واجهة برمجة التطبيقات (على سبيل المثال مع .on("error", function(error) {...}) ) ، فلن يصلوا إلى Mocha أبدًا ما لم تستمع إليهم ولديك يستدعي المستمع done مع الخطأ (أو استخدم فقط done مع المستمع إذا مر المستمع بالخطأ كمعامله الأول ، على سبيل المثال .on("error", done) . من المفترض أن هذا سيفترض أيضًا فقط يجب كتابتها مرة واحدة لكل اختبار ، بدلاً من مرة واحدة لكل معالج حدث ، مثل .catch(done) في الوعد.
  1. نعم ، وأنا أستخدم حدثًا "end" / "drain" للتحقق مما إذا تم تعيين القيم المنطقية في الأحداث الأخرى.
  2. المهلة تحدث. أحاول إيجاد بديل رشيق ونظيف.

عذرًا ، ما زلت لا أعرف كيف يُفترض أن تبلغ واجهة برمجة التطبيقات API عن الأخطاء.

نعم ، لقد كنت أعتمد حتى الآن على المهلات الزمنية لـ _عندما تفشل بعض الأشياء ، ثم أحفر يدويًا لاكتشاف _كيف / لماذا _. لحسن الحظ ، نادراً ما تنكسر الأشياء ، لكن هذا ليس عذراً لعدم وجود تصميم أفضل (من جانبي ، في الغالب).

stevenvachon : سامحني مقدمًا ، لكنني لا أرى مشكلة فورية في uncaughtException (ما لم يكن تنفيذ باعث الحدث يصطاد أخطاء المستمع ويصدر حدث error أو شيء ما ، والذي لا يزال من السهل بعد ذلك يحل).

الآن ، إذا كان تنفيذك تحت غطاء المحرك يستخدم الوعود ، لكنه يرسل الأحداث بدلاً من فضح الوعد ، فإن تأكيداتك ستُؤكل بالفعل. الطريقة التي يمكنني بها التغلب على هذه المشكلة هي استخدام unhandledRejection .

عادةً ما أضع هذا في برنامج نصي للإعداد يتم تشغيله قبل اختباراتي:

process.on('unhandledRejection', function (reason)
{
    throw reason;
});

ملاحظة: قد يحتاج هذا إلى بعض الشحوم الإضافية للعمل في المتصفحات.

آمل أن أرى Mocha يدعم هذا كما يفعل uncaughtException لأن هذه حالة استخدام شائعة ؛ لمجرد أنني أستخدم الوعود لا يعني أنني أريد إعادتها إلى المتصل!

تواجه نفس المشكلة مع

    it('Convert files into base64', (resolve) => {
        let files = Promise.all(promises);

        return files
            .then(([actual, expected]) => {
                assert.equal(actual, expected, 'Files not are equal');
                resolve();
            })
            .catch(error => resolve);
    });
   Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

.catch خطأ. error => resolve يعادل function(error) { return resolve } ، مما يعني أنه لن يتم استدعاء resolve وسيتم تجاهل الخطأ. ما تريده هو استدعاء resolve مع ظهور الخطأ ، والذي سيكون error => resolve(error) . بالطبع ، تمرير دالة رد الاتصال X التي تستدعي ببساطة الوظيفة Y بنفس الوسيطات التي يُطلق عليها X تعادل مجرد تمرير Y مثل رد الاتصال ، لذلك حتى .catch(error => resolve(error)) يمكن تبسيطها إلى .catch(resolve) . (ستحتاج فقط إلى عدم تمرير resolve مباشرةً إذا كنت تمرره إلى then ، وبالتالي ، هناك حاجة لتجنب تمرير معامل النتيجة then إلى resolve لمنع معاملته كخطأ: then(()=>resolve()) بدلاً من .then(resolve) ؛ ولكن نظرًا لأنك تستخدم رد الاتصال then للتأكيدات ، فإن هذا لا يحدث .)

(أيضًا ، بشكل اصطلاحي ، من المحتمل أن يتم تسمية resolve هنا بشيء على غرار done ، لأنه يتعامل مع كل من النجاح والفشل والقضاة الذي يعتمد على ما إذا كان قد تم استدعاؤه بحجة أو لا. ومن هنا الاسم الوارد في رسالة الخطأ الخاصة بـ Mocha. ولكن قد تكون هذه نقطة خلافية ؛ واصل القراءة.)

ومع ذلك ، في هذه الحالة ، يمكنك تبسيطها أكثر من خلال إعادة الوعد فقط وعدم استخدام معلمة الاختبار التي تم إجراؤها على الإطلاق ، حيث ستنتظر Mocha الوعد بالنجاح أو الفشل كإشارة إلى نجاح الاختبار أو فشله (بشرط عدم وجود معلمة تم إجراؤها وظيفة الاختبار ؛ السلوك في حالة استخدام كليهما لا يزال قيد التجزئة):

it('Convert files into base64', () => {
    let files = Promise.all(promises);
    return files
        .then(([actual, expected]) => {
            assert.equal(actual, expected, 'Files not are equal');
        })
});

lsphillips التي تناسبني. شكرا!! آمل أن أرى المخاوي يدعم هذا بشكل افتراضي أيضًا. لقد خلقت للتو # 2640.

استغرقت مني بعض الوقت لأعمل على ذلك! بناءً على الإجابات أعلاه ، هذان هما الخياران:

npm install --save mocha expect.js q
./node_modules/mocha/bin/mocha test.spec.js

// test.spec.js

var $q = require('q');
var expect = require('expect.js');

describe('tests with done', function(){
    it('returns the correct value from promise', function(done) {
      var returnValue = 5;
      var def = $q.defer();
      def.promise.then((val) => {
        expect(val).to.equal(42);
        done();
      }).catch(done);
      def.resolve(returnValue)
    });
})

describe('tests returning promises', function(){
    it('returns the correct value from promise', function() {
      var returnValue = 5;
      var def = $q.defer();
      def.resolve(returnValue)
      return def.promise.then((val) => {
        expect(val).to.equal(42);
      });
    });
})
  tests with done
    1) returns the correct value from promise

  tests returning promises
    2) returns the correct value from promise


  0 passing (15ms)
  2 failing

  1) tests with done returns the correct value from promise:
     Error: expected 5 to equal 42
      at Assertion.assert (node_modules/expect.js/index.js:96:13)
      at Assertion.be.Assertion.equal (node_modules/expect.js/index.js:216:10)
      at def.promise.then (tests/test.spec.js:9:24)
      at _fulfilled (node_modules/q/q.js:854:54)
      at self.promiseDispatch.done (node_modules/q/q.js:883:30)
      at Promise.promise.promiseDispatch (node_modules/q/q.js:816:13)
      at node_modules/q/q.js:570:49
      at runSingle (node_modules/q/q.js:137:13)
      at flush (node_modules/q/q.js:125:13)
      at _combinedTickCallback (internal/process/next_tick.js:67:7)
      at process._tickCallback (internal/process/next_tick.js:98:9)

  2) tests returning promises returns the correct value from promise:
     Error: expected 5 to equal 42
      at Assertion.assert (node_modules/expect.js/index.js:96:13)
      at Assertion.be.Assertion.equal (node_modules/expect.js/index.js:216:10)
      at def.promise.then (tests/test.spec.js:22:24)
      at _fulfilled (node_modules/q/q.js:854:54)
      at self.promiseDispatch.done (node_modules/q/q.js:883:30)
      at Promise.promise.promiseDispatch (node_modules/q/q.js:816:13)
      at node_modules/q/q.js:570:49
      at runSingle (node_modules/q/q.js:137:13)
      at flush (node_modules/q/q.js:125:13)
      at _combinedTickCallback (internal/process/next_tick.js:67:7)
      at process._tickCallback (internal/process/next_tick.js:98:9)

gurdiga شكرا

في السيناريو الخاص بي ، استخدمت Nightmare لإنهاء الاختبارات. كان الحل بالنسبة لي هو استخدام .catch(done) . يمكنك الاتصال بـ done(error) داخل رد اتصال آخر كما في المثال أدناه.

describe('Clicking in any bad reputation tag', () => {
    it('open the bad reputation modal', (done) => {
      nightmare
        .select('#per-page', '50')
        .waitForAjax()
        .click('[data-reputation="bad"]')
        .evaluate(function() {
          return document.querySelector('.vue-modal .ls-modal-title').innerText
        })
        .then(function(title) {
          title.should.equal('Sua segmentação teve uma avaliação ruim!')
          done()
        })
        .catch((error) => {
          screenshot(nightmare)
          done(error)
        })
    })
  })

itumoraes يعمل ، ولكن يمكنك القيام بذلك بدلاً من ذلك:

describe('Clicking in any bad reputation tag', () => {
    it('open the bad reputation modal', () => {
      return nightmare
        .select('#per-page', '50')
        .waitForAjax()
        .click('[data-reputation="bad"]')
        .evaluate(function() {
          return document.querySelector('.vue-modal .ls-modal-title').innerText
        })
        .then(function(title) {
          title.should.equal('Sua segmentação teve uma avaliação ruim!')
        })
    })
  })

لا تحتاج إلى الاتصال بـ done() إذا عدت بوعد. شاهد منشور مدونتي

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

مخطوطة:

وصف ("getBillingDetail"، دالة غير متزامنة () {
this.timeout (55000) ؛
it.only ("تحقق من إعطاء اسم عمل صالح" ، وظيفة غير متزامنة (تم) {
this.timeout (55000) ؛
var نتيجة = await url.getBillingDetail ('12254785565647858') ؛
console.log (نتيجة) ؛
assert.equal (نتيجة ، صواب) ؛
}) ؛
}) ؛

خطأ: تجاوز المهلة 55000 مللي ثانية. بالنسبة للاختبارات غير المتزامنة والخطافات ، تأكد من استدعاء "تم ()" ؛ في حالة إعادة الوعد ، تأكد من أنه يقرر.

توقف عن تهجئة نفس الشيء في العديد من القضايا المغلقة. لا تمرر رد اتصال تم إلى وظائف غير متزامنة. اقرأ الوثائق الخاصة باختبارات عدم التزامن

Munter قمت بإزالة رد الاتصال الذي تم القيام به ، ولكن حدث هذا الخطأ مرة أخرى

يبدو أن وعدك لم يتم إعادة صياغته أبدًا.

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