Sinon: Mungkinkah mematikan fungsi utilitas mandiri?

Dibuat pada 12 Sep 2014  ·  18Komentar  ·  Sumber: sinonjs/sinon

Banyak modul node mengekspor satu fungsi (bukan fungsi konstruktor, tetapi fungsi "utilitas" tujuan umum) sebagai "module.exports" -nya. Apakah mungkin menggunakan Sinon.js untuk mematikan fungsi mandiri ini?

// some module, "sum.js" that's "required" throughout the application
module.exports = function(a, b) {
    return a + b;
};

// test.js
var sum = require('sum');
...

beforeEach(function() {
    sumStub = sinon.stub(sum);
    // throws: TypeError: Attempted to wrap undefined property undefined as function
});

afterEach(function() {
   sumStub.restore();
});
...

Apakah ada cara untuk mencapai hal ini?

Komentar yang paling membantu

Coba ini

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

Semua 18 komentar

Sayangnya tidak.

Untuk npm Anda dapat menggunakan https://github.com/thlorenz/proxyquire atau yang serupa. Michael Feathers akan menyebutnya sebagai link seam .

Ini tidak elegan, tapi bisa dilakukan.

Setelah Anda memilikinya, Anda dapat menggunakan Sinon seperti biasa.

Dalam jangka panjang, Anda mungkin ingin memindahkan arsitektur Anda ke _object seams_, tetapi ini adalah solusi yang berfungsi saat ini. Proyek serupa ada untuk RequireJS.

function MyFunction(){}
module.exports = function(){ return module.exports.MyFunction.apply(this, arguments) }
module.exports.MyFunction = MyFunction

Kemudian Anda dapat stub require('./MyFunction').MyFunction dan sisa kode Anda akan tanpa perubahan melihat edisi stub.

:pusing: :pusing_wajah: :pusing:

Tersandung di hal yang sama tempo hari, inilah yang saya lakukan:

const proxyquire = require('proxyquire')
const sinon = require('sinon')
const sum = sinon.stub()

const ModuleWithDependency = proxyquire('module', {
  'sum': sum
})

bekerja cukup baik untuk kasus kami.

Jika menggunakan CommonJS:

const myStubbedModule = function( absoluteModulePath ) {
  const stub = sinon.stub();
  require.cache[ require.resolve( absoluteModulePath ) ] = stub;
  return stub;
}

_Note_: Bergantung pada apakah Anda melakukan transpiling, Anda mungkin perlu melakukan:

require.cache[ require.resolve( absoluteModulePath ) ] = {
  default: stub,
  exports: stub
}

Seringkali selama tes saya harus memasukkan satu rintisan untuk satu tes tertentu. Pendekatan fungsi pembungkus yang saya ambil memungkinkan saya memodifikasi basis kode dan memasukkan rintisan saya kapan pun saya mau, tanpa harus mengambil pendekatan rintisan pertama atau memainkan whack-a-mole dengan modul yang memiliki referensi ke modul lain yang saya coba rintisan dan ganti di tempat.

Saya memiliki sejumlah ulasan kode di mana orang-orang telah mendorong saya untuk meretas pada lapisan modul Node, melalui proxyquire, mock-require , &c, dan itu mulai sederhana dan tampaknya tidak terlalu kasar, tetapi menjadi tantangan yang sangat sulit untuk mendapatkan stub diperlukan pada tempatnya selama pengaturan pengujian. Dengan proxyquire setidaknya satu dapat proxyquire() versi aplikasi berukuran mikro/perlengkapan, sesuatu tingkat atas, & semua rintisan akan dibawa selama pemuatannya, tetapi menangani ini pada tingkat bahasa JS daripada tingkat modul Node berlanjut untuk menyerang saya secara signifikan lebih mudah, dan lebih mudah untuk mengelola secara konsisten dan tanpa bahaya (peringatan: selama orang ingat untuk memulihkan).

Saya membuat modul ini agar modul stub lebih mudah https://github.com/caiogondim/stubbable-decorator.js

Saya baru saja bermain dengan Sinon dan menemukan solusi sederhana yang tampaknya berhasil - tambahkan saja 'argumen' sebagai argumen kedua

const sumStub = sinon.stub(sum, 'arguments');
sumStub.withArgs(2, 2).returns(4);
sumStub.withArgs(3, 3).returns(6);

Coba ini

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

@harryi3t - terima kasih itu berhasil untuk saya.

@harryi3t Itu tidak berhasil untuk saya, menggunakan Modul ES.
Kesalahan: can't redefine non-configurable property "default"

@elliottregan ES Modules tidak dapat dihentikan sesuai STANDAR. Kami bahkan memiliki tes yang mencakup perilaku saya bahas di sini .

Banyak orang sebenarnya tidak menguji Modul ES, tetapi mengubah Modul ES (menggunakan Webpack/Babel, dll). ES5 yang dihasilkan menggunakan getter untuk meniru cara kerja Modul ES. Anda mungkin melakukan itu, tetapi coba rute sederhana yang saya sarankan di utas tertaut. mocha --register ... membuat Anda jauh.

Kemungkinan solusi

(function (defineProperty) {
    Object.defineProperty = (obj, prop, desc) => {
        desc.configurable = true;
        return defineProperty(obj, prop, desc);
    };
})(Object.defineProperty);

@Sujimoshi Solusi untuk apa sebenarnya? Apa konteks untuk perbaikan Anda? Juga, di mana orang akan memperbaikinya? Dalam inkarnasinya saat ini, ia kehilangan terlalu banyak info untuk membantu. Itu tidak akan membantu pertanyaan awal dan tidak akan berfungsi untuk ES Modules . Saya menduga itu menyangkut kode yang telah diproses oleh Webpack 4, karena mungkin berlaku (tergantung pada rantai alat Anda) untuk kode yang ditulis menggunakan sintaks ES2015+ yang telah _transpiled_ menjadi ES5, _emulating_ kekekalan Modul ES melalui deskriptor objek yang tidak dapat dikonfigurasi .

Coba ini

import * as sum from './sum'
sinon.stub(sum, 'default', () => {
  // stubbed function
});

ditinggalkan sekarang.

Saya baru saja menulis ulang modul ES6 saya dari ini:

export default const doCoolStuff = () => {
  // do the cool stuff...
}

untuk ini:

export default {
  doCoolStuff: () => {
    // do the cool stuff...
  }
} 

Agak kikuk, tetapi memungkinkan saya untuk membungkus fungsi dalam sebuah rintisan.

sekarang sudah hampir tahun 2021, apakah mungkin?

sekarang sudah hampir tahun 2021, apakah mungkin?

Tidak jauh berbeda dengan tahun 2019.
Modul ES tidak berubah, CommonJS tidak berubah, JavaScript tidak berubah.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat