Mocha: Tes async gagal dengan batas waktu alih-alih kesalahan pernyataan

Dibuat pada 5 Feb 2014  ·  25Komentar  ·  Sumber: mochajs/mocha

Tes ini:

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

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

    });

Tes ini gagal dengan timeout of 2000ms exceeded alih-alih kesalahan pernyataan. Saya kira itu karena panggilan expect() menimbulkan kesalahan, dan done() tidak pernah dieksekusi, dan saya ingin tahu apakah ada cara yang lebih baik untuk menguji kode semacam ini.

Komentar yang paling membantu

Saya mengalami masalah yang sama, dan akhirnya menyadari bahwa Anda tidak boleh menggunakan done saat menguji fungsi asinkron dengan janji, sebagai gantinya, kembalikan saja janjinya. Jadi, Anda harus dapat melakukan ini tanpa batas waktu, misalnya:

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

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

Semua 25 komentar

Apakah aPromise pernah diselesaikan? Jika tidak, tidak ada banyak pilihan selain membuang waktu.

@NickHeiner Ya, itu menyelesaikan; dan kemudian expect() menemukan returnValue bukan equal(42) dan melempar.

@gurdiga bagaimana Anda tahu itu melempar jika Anda mendapatkan batas waktu dan bukan kesalahan pernyataan?

@hallas @NickHeiner Inilah yang sedang berjalan: http://jsfiddle.net/gurdiga/p9vmj/.

@gurdiga menurut saya janji Anda memiliki kesalahan sendiri. Coba tambahkan .catch(done) ke janji Anda dan saya pikir itu akan berfungsi sebagaimana mestinya.

@hallas Wow: _itu_ adalah jawabannya! :) aPromise.finally() tampaknya sangat cocok untuk memasukkan done ke dalam: itu juga perlu dipanggil ketika janji diselesaikan. ;)

Terima kasih!

Aku merasa bodoh.

Saya pikir saya akhirnya mendapatkannya: ketika ada yang melempar salah satu fungsi penangan janji, baik itu yang diteruskan ke .then() , ke .catch() atau ke .finally() , kesalahannya adalah ditangani oleh perpustakaan janji. Dengan cara ini, test runner tidak akan pernah melihat kesalahan yang sebenarnya, done() tidak pernah dipanggil (karena sesuatu sebelum ia melontarkan kesalahan pernyataan), jadi hanya kesalahan time out yang Anda dapatkan dari test runner.

Untuk keluar dari janji, saya menggunakan setTimeout() :

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

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

Saya menemukan ini adalah satu-satunya cara untuk mendapatkan pesan kesalahan yang tepat dan menguji perilaku pelari.

Dengan done diteruskan ke .catch() atau .finally() tes dianggap lulus dalam hal apa pun, jadi jika ada kesalahan pernyataan, Anda tidak akan pernah melihatnya.

Saya mengalami masalah yang sama, dan akhirnya menyadari bahwa Anda tidak boleh menggunakan done saat menguji fungsi asinkron dengan janji, sebagai gantinya, kembalikan saja janjinya. Jadi, Anda harus dapat melakukan ini tanpa batas waktu, misalnya:

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

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

Saya pikir masalah ini masih ada. Saya mendapatkan masalah batas waktu yang tidak dapat diselesaikan dengan mengembalikan janji karena modul saya tidak menggunakan janji.

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();
    });
});
  • Membungkus instance dalam Promise tampaknya berlebihan.
  • Membungkus setiap pernyataan dalam try / catch juga tampaknya berlebihan dan, yang lebih penting, menghasilkan Error: done() called multiple times .

Ide ide:
http://staxmanade.com/2015/11/testing-asyncronous-code-with-mochajs-and-es7-async-await/

Mengenai rekomendasi posting blog, saya tidak tahu tentang penanganan kesalahan fungsi async, tetapi untuk janji biasa, rekomendasi try-catch aneh: upaya janji asli tanpa try-catch hampir benar, hanya perlu menggunakan .catch(done) alih-alih menggunakan parameter kedua ke then sebagai done . (Memang, karena Mocha memiliki dukungan langsung untuk janji, Anda juga dapat mengembalikan janji, tetapi untuk apa nilainya...) Masalah dalam contoh janji awal bukanlah tidak adanya try-catch, itu adalah handler kedua ke then tidak dipanggil dengan pengecualian yang dilontarkan oleh handler pertama, sedangkan catch adalah; Saya tidak tahu apa alasannya untuk janji dirancang seperti itu, tapi begitulah janji. Selain itu, jika ada beberapa then s karena alasan tertentu, hanya diperlukan satu .catch(done) final, yang merupakan titik keunggulan dibandingkan try-catch di dalam handler (di atas fakta bahwa .catch(done) lebih sedikit boilerplatey untuk memulai).

Adapun API Anda:

  1. Apakah Anda yakin kedua acara tersebut dipanggil, dan dalam urutan yang benar? Jika tidak, bagaimana pengujian Anda mengubahnya menjadi kegagalan normal?
  2. Apa yang biasanya terjadi pada pengecualian yang dilemparkan dari pengendali acara Anda? Jika mereka tidak menyebar seperti yang mereka lakukan dalam kode sinkron dan sebaliknya dimaksudkan untuk didengarkan di API (misalnya dengan .on("error", function(error) {...}) ), maka mereka tidak akan pernah mencapai Mocha kecuali Anda mendengarkan mereka dan memiliki pendengar memanggil done dengan kesalahan (atau cukup gunakan done dengan pendengar jika pendengar melewatkan kesalahan sebagai parameter pertamanya, misalnya .on("error", done) . Agaknya itu juga hanya perlu ditulis sekali per pengujian, bukan sekali per event handler, seperti .catch(done) dalam janji.
  1. Ya, dan saya menggunakan acara "end" / "drain" untuk memeriksa apakah boolean di acara lain disetel.
  2. Batas waktu terjadi. Saya mencoba mencari alternatif yang ramping dan bersih.

Maaf, saya masih tidak tahu bagaimana seharusnya API Anda melaporkan kesalahan.

Ya, sejauh ini saya hanya mengandalkan batas waktu untuk _kapan_ sesuatu gagal, lalu menggali secara manual untuk mencari tahu _bagaimana/mengapa_. Untungnya, hal-hal jarang rusak, tapi itu bukan alasan untuk kurangnya desain yang lebih baik (di bagian saya, kebanyakan).

@stevenvachon : Maafkan saya sebelumnya, tapi saya tidak melihat masalah langsung dengan contoh Anda. Pernyataan yang dibuat di pendengar acara Anda harus ditangani oleh Mocha melalui pemetaan uncaughtException (kecuali implementasi emitor acara menangkap kesalahan pendengar dan memancarkan acara error atau sesuatu, yang kemudian masih mudah untuk menyelesaikan).

Sekarang jika implementasi Anda di bawah tenda menggunakan Janji, tetapi memancarkan peristiwa daripada mengekspos Janji, pernyataan Anda memang akan "dimakan". Cara saya mengatasi masalah ini adalah dengan menggunakan unhandledRejection .

Saya biasanya meletakkan ini di skrip pengaturan yang dijalankan sebelum pengujian saya:

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

Catatan: Ini mungkin memerlukan beberapa minyak siku ekstra untuk bekerja di browser.

Saya berharap untuk melihat Mocha mendukung ini seperti yang dilakukannya uncaughtException karena ini adalah kasus penggunaan yang umum; hanya karena saya menggunakan Janji bukan berarti saya ingin mengembalikannya ke pemanggil!

Memiliki masalah yang sama dengan [email protected]

    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 salah. error => resolve setara dengan function(error) { return resolve } , yang berarti resolve tidak akan dipanggil dan kesalahan diabaikan. Yang Anda inginkan adalah memanggil resolve dengan kesalahan, yang akan menjadi error => resolve(error) . Tentu saja, meneruskan fungsi panggilan balik X yang hanya memanggil fungsi Y dengan argumen yang sama dengan yang dipanggil X sama dengan melewatkan Y sebagai panggilan balik, jadi bahkan .catch(error => resolve(error)) dapat disederhanakan menjadi .catch(resolve) . (Anda hanya perlu tidak meneruskan resolve secara langsung jika Anda meneruskannya ke then dan, oleh karena itu, perlu menghindari meneruskan parameter hasil then ke resolve untuk mencegahnya diperlakukan sebagai kesalahan: then(()=>resolve()) bukan hanya .then(resolve) ; tetapi karena Anda menggunakan panggilan balik then untuk pernyataan, ini tidak muncul .)

(Juga, secara idiomatis, resolve sini mungkin harus dinamai sesuatu di sepanjang baris done , karena menangani keberhasilan dan kegagalan dan menilai yang didasarkan pada apakah itu dipanggil dengan argumen atau tidak. Oleh karena itu nama dalam pesan kesalahan Mocha. Tapi itu mungkin poin yang bisa diperdebatkan; baca terus.)

Namun, dalam hal ini Anda dapat menyederhanakannya lebih jauh dengan hanya mengembalikan janji dan tidak menggunakan parameter test done sama sekali, karena Mocha akan menunggu janji untuk berhasil atau gagal sebagai indikasi keberhasilan atau kegagalan pengujian (asalkan tidak ada parameter done untuk fungsi tes; perilaku jika keduanya digunakan masih di-hash):

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

@lsphillips yang bekerja untuk saya. Terima kasih!! Saya berharap untuk melihat mocha mendukung ini secara default juga. Saya baru saja membuat #2640.

Butuh beberapa saat untuk menyelesaikan ini! Berdasarkan jawaban di atas , ini adalah dua opsi:

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 Terima kasih atas ide setTimeout()! Saya memiliki masalah yang sama, tetapi sekarang saya bisa mendapatkan pesan kesalahan yang tepat setidaknya!

Dalam skenario saya, saya menggunakan Nightmare untuk mengakhiri tes. Solusi bagi saya adalah menggunakan .catch(done) . Anda dapat memanggil done(error) di dalam catch callback lainnya seperti contoh di bawah ini.

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 yang berfungsi, tetapi Anda dapat melakukan ini sebagai gantinya:

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!')
        })
    })
  })

Anda tidak perlu menelepon done() jika Anda mengembalikan janji. Lihat posting blog saya Menggunakan Async/Menunggu dengan Mocha, Express, dan Mongoose

saya menggunakan skrip di bawah ini tetapi saya mendapatkan kesalahan melebihi batas waktu yang sama.

Skrip saya:

deskripsikan("getBillingDetail", fungsi asinkron (){
this.timeout(55000);
it.only("periksa nama pekerjaan yang diberikan valid", fungsi async (selesai){
this.timeout(55000);
var hasil = menunggu url.getBillingDetail('1225478565647858');
console.log(hasil);
menegaskan.sama(hasil,benar);
});
});

Kesalahan: Batas waktu 55000 ms terlampaui. Untuk pengujian dan pengait asinkron, pastikan "selesai()" dipanggil; jika mengembalikan Janji, pastikan itu terselesaikan.

Berhenti mengeja hal yang sama dalam beberapa masalah tertutup. Jangan meneruskan panggilan balik yang sudah selesai ke fungsi async. Baca dokumentasi tentang tes async

@Munter saya menghapus panggilan balik yang dilakukan, tetapi kesalahan ini terjadi lagi

Sepertinya janjimu tidak pernah ditepati.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat