Sinon: Spy `returnValue` tidak bekerja dengan generator

Dibuat pada 3 Jan 2015  ·  20Komentar  ·  Sumber: sinonjs/sinon

Saat bekerja dengan fungsi generator, nilai kembalian mata-mata selalu undefined . Inilah kasus uji yang gagal:

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

Jalankan dengan npm install co mocha should sinon && ./node_modules/.bin/mocha --harmony index.js .

2.x Unverified

Semua 20 komentar

Sinon belum mendukung fitur ES6. Pengerjaan ini belum dimulai, jadi saya tidak tahu kapan ini akan berhasil.

@mantoni , kan, ini lebih merupakan permintaan fitur :) apakah Anda ingin membiarkannya terbuka, misalnya, dengan semacam tag ("es6"?) sehingga ketika itu ditambahkan ke peta jalan lebih mudah untuk kembali -evaluasi apa yang perlu dilakukan?

Ini akan menjadi fitur yang bagus untuk dimiliki.

@ruimarinho saya menemukan ini https://github.com/ingameio/SinonES6.JS
mengganti require("sinon") dengan require("sinon-es6") tampaknya membuat tes Anda lulus

--
diedit oleh @fatso83 pada 22 Juni 2017:
Ini sepertinya tidak benar. Saya menguji ini secara manual. Semuanya gagal, yang masuk akal karena sinon-es6 _hanya mengimplementasikan dukungannya untuk generator untuk mengejek _.

Apakah ada yang mengerjakan ini?

@emgeee bukan yang saya sadari.

+1 @ruimarinho sinon.js dengan fitur es6 akan luar biasa untuk dimiliki!

@ingameio peduli untuk membuat PR dengan perubahan Anda?

@fatso83 terima kasih atas sarannya!
Aku akan mengerjakan PR segera ;)

Saya mengalami masalah saat menjalankan uji buster terhadap versi paket. Saya melakukan beberapa debugging tetapi saya kekurangan waktu hari ini sehingga saya tidak dapat menyelesaikan masalah.
Jika seseorang ingin membantu saya dapat mendorong perubahan ke garpu saya, beri tahu saya dan saya akan melakukannya.

@gaguirre Itu adalah berita bagus. Maximillian baru saja mengonversi semua tes ke Mocha, dan melakukan beberapa perubahan dalam pengaturan tes saat melakukannya, jadi mungkin semuanya berhasil jika Anda menarik perubahan terbaru dari master ?

@gaguirre Jika seseorang tersandung pada utas ini, saya pikir itu bisa menjadi ide untuk mendorong perubahan ke garpu Anda sehingga orang yang lewat dapat melihatnya.

@fatso83 Saya mendorong versi pertama ke underscope/sinon .
Masalah utama terjadi ketika menjalankan tes dengan mesin yang tidak mendukung es6 (phantomjs dalam kasus ini): gagal saat menguraikan kode jadi saya menggunakan eval() sebagai solusi karena dapat dikelilingi oleh try/ menangkap. Saya pikir ini tidak dapat diterima tetapi ini adalah titik awal.

Saat ini saya mencoba untuk membungkus panggilan generator di file lain dan memerlukannya secara dinamis, tetapi tidak berfungsi, saya kira karena browserify itu membundel bahkan file yang diperlukan secara dinamis. Saya ingin tahu apakah beberapa file dapat dikecualikan saat menjalankan npm run test-headless .

Apa yang menurut Anda bisa menjadi solusi terbaik?

Terima kasih atas umpan baliknya, @gaguirre . Jadi masalah dasarnya adalah kita memerlukan beberapa cara untuk menghindari penguraian jika mesin tidak mendukungnya. Itu sedikit lebih sulit daripada deteksi fitur sederhana, seperti yang kami lakukan dengan WebWorkers, dll.

Hanya mendelegasikan cek yang sebenarnya sesederhana if(require('generator-support')){ ... } , tetapi ini tidak memperbaiki masalah penguraian yang sebenarnya.

Adakah ide tentang cara menangani ini dengan bersih, @mantoni dan @mroderick?

PS Saya pergi pada liburan offline dalam beberapa jam, jadi tidak akan dapat membaca jawaban sampai beberapa waktu setelah Paskah.

Saya tidak tahu apakah tingkat penghentian generator ini benar-benar berfungsi (terutama dalam skenario berorientasi coroutine) - tampaknya beberapa emulasi perilaku async mungkin sesuai. Tapi saya pikir ada cara mengatasi masalah parsing.

Saran :

Ekstrak kode generator ke dalam file terpisah dan require() file itu hanya sesuai permintaan saat membungkus fungsi generator, yaitu:

?/es6-support.js:

"use strict";

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

lib/sinon/mock.js->mengharapkan...:

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);

(Juga lakukan hal yang serupa dengan pengujian unit, dan pastikan pelacakan cakupan kode tidak menyebabkan file 'dukungan es6' disertakan secara otomatis.)

Saran alternatif :

Apakah kompatibilitas ES5 masih akan menjadi tujuan yang berharga pada saat sinon 2.0 siap dirilis? Mungkin sudah waktunya untuk memberi tahu beberapa orang yang masih mendukung lingkungan warisan ES5 saja tanpa pengguna transpiler bahwa mereka akan tertinggal di 1.x.

@evan-king Persyaratan bersyarat itu bukanlah solusi, karena akan rusak di build browser kami. Karena kondisional memerlukan analisis statis dari grafik ketergantungan, alat seperti WebPack, Rollup, dan Browserify tidak akan dapat menanganinya. Ini benar-benar masuk atau benar-benar keluar.

Dan ya, kompatibilitas ES5 adalah suatu hal. Dukungan generator ES6 sangat buruk, dan memaksa orang untuk menggunakan alat tambahan untuk menggunakan Sinon untuk proyek mereka akan meningkatkan standar untuk melakukan pengujian. Dan bagi banyak orang, ambang batas itu cukup tinggi. Mampu memasukkan tag skrip sederhana untuk membuatnya berfungsi adalah fitur penting IMHO. Kami mungkin akan merusak kompatibilitas ES5 pada suatu waktu, tetapi itu tidak ada dalam peta jalan kami dan bahkan belum dibahas untuk Sinon 3. Sinon 2 sebenarnya telah keluar untuk beberapa waktu; hanya ada beberapa gangguan kecil yang menghentikan kami untuk melakukan rilis resmi.

Pada dasarnya ada dua cara untuk mendapatkan kompatibilitas ES6 tanpa merusak kompatibilitas runtime ES5 yang ada yang dapat saya buat, dan saya tidak begitu yakin tentang yang terakhir (belum mengujinya):

Evaluasi bersyarat modul

Ini adalah peretasan, tetapi cukup sederhana. Artinya, kita dapat mengandalkan inlining aset statis dan pengujian fitur ES6 untuk memutuskan apakah akan mengevaluasi modul yang diperlukan. Ini akan memastikan kompatibilitas ES5 (Sinon hanya akan ditambal jika runtime mendukung sintaks), tidak perlu alat tambahan dalam bentuk Babel baik di sisi pembuat perpustakaan maupun pengguna klien, dan pengujian ES6 akan merusak browser ES5 yang akan gagal dalam hal apapun.

Dengan asumsi sesuatu seperti brfs ada di tempatnya, kodenya akan terlihat seperti ini:

_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"); }
}

Membabel Sinon

Ini yang saya tidak yakin karena saya belum benar-benar mencobanya. Jika kita melakukan transpile build melalui Babel ke ES5, kita dapat menulis kode ES6 di semua tempat, menghindari melompati rintangan seperti yang saya lakukan di atas, dan kita masih dapat menggunakan jenis pemeriksaan yang sama untuk generator. Mereka hanya akan diimplementasikan menggunakan konstruksi ES5. Tentu saja, pengujian ES6 di browser ES5 akan tetap gagal. Ini memiliki keuntungan yang sama dengan yang sebelumnya di sisi klien, tetapi kami mungkin menghalangi kontribusi karena pengetahuan ES2015 tentang hal-hal seperti yield , async , function*() masih jauh dari jangkauan khalayak luas.

+1

@rpavlovs , benar-benar tidak ada gunanya menambahkan +1 ke utas. GitHub UI memiliki tombol "tambahkan reaksi" di atas setiap komentar jika Anda perlu mengekspresikan emosi Anda. A +1 tidak akan menghasilkan apa-apa. Permintaan tarik yang menerapkan salah satu saran di atas (atau sesuatu yang lebih pintar), di sisi lain, memiliki peluang yang jauh lebih baik untuk memperbaiki masalah ini

Saya ingin masukan tentang bagaimana dukungan API untuk generator akan terlihat , karena setelah menggunakan beberapa jam untuk ini, saya masih tidak begitu yakin apa yang ingin dilihat orang.

Untuk mulai menyempurnakan ini, saya telah membuat cabang baru yang menampung modifikasi @ingameio ke api tiruan, sementara pada saat yang sama tidak melanggar kompatibilitas ES5 (menggunakan peretasan yang disebutkan di atas).

Yang sedikit membuat saya kesal adalah bahwa saya benar-benar tidak tahu cara menguji perubahan asli oleh Ingameio, karena tidak ada contoh pengujian yang berfungsi - bahkan contoh di fork tidak lengkap, dan saya tidak dapat memecahkan barang sebelum/sesudah perubahan.

Generator adalah hal-hal sederhana: makhluk sinkron lembut yang mengingat masa lalu mereka. Jadi tolong jangan teka-teki contoh apa pun dengan co dan hal-hal lain yang tidak terkait, karena akan mempersulit untuk melihat apa yang diinginkan/tidak berfungsi. Contoh teratas misalnya cukup rumit, dan tampaknya juga salah mengira apa yang dilakukan yield , karena mengharapkan nilai kembalian "ekspresi hasil" sama dengan "nilai hasil". result dari hasil adalah nilai yang diteruskan ke next() generator ( MDN )

Saya menyadari contoh menggunakan co mungkin hanya menggunakannya untuk dapat menggunakan yield secara langsung dalam tes Mocha, tetapi cukup bungkus contoh Anda dalam IIFE atau cara lain untuk mencapai hal yang sama untuk demi kejelasan lebih.

Ini adalah tes sederhana tentang bagaimana generator mendukung (bekerja di Sinon hari ini):

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();
    });
});

Sekarang, ekstensi API apa yang kita inginkan?
Dari tes asli, saya berasumsi kita ingin melihat sesuatu seperti

foo.biz.firstGeneratedValue.should.equal('biz');
atau
foo.biz.generatedValue[0].should.equal('biz');
?

cc @ruimarinho

Saya menutup masalah ini, karena pengujian asli memiliki kesalahan, dan saya tidak dapat melihat masalah apa pun dengan penanganan generator di Sinon.

Silakan bergabung dalam diskusi tentang bagaimana API untuk menangani generator (dan iterator terkaitnya) akan terlihat di edisi #1467

Apakah halaman ini membantu?
0 / 5 - 0 peringkat