Baru-baru ini, saya beralih kepada menggunakan Suntikan Kebergantungan untuk membantu memahami cara mudah untuk memisahkan kod dan membantu dalam ujian. Walau bagaimanapun, modul dalam Node.js bergantung pada API sistem yang disediakan oleh Node, yang menyukarkan untuk menilai sama ada kebergantungan persendirian digunakan dengan sewajarnya. Suntikan pergantungan am adalah sukar untuk digunakan dalam kes ini, tetapi jangan berputus asa dahulu.
memerlukanPunca masalah
Node.js boleh mengimport kebergantungan dengan mudah mengikut keperluan. Ia berfungsi dengan baik dan lebih mudah daripada pemuat skema AMD seperti RequireJS. Masalahnya datang apabila kita mengejek kebergantungan tersebut. Jika pemuatan model dalam Node.js dikawal, bagaimanakah kita boleh mengawal objek pseudo yang digunakan semasa ujian? Kita boleh menggunakan mod vm Node, melalui vm kita boleh memuatkan model dalam konteks baharu. Berjalan dalam konteks baharu, kita boleh mengawal cara keperluan ditunjukkan ke dalam kaedah model.
Penyelesaian
Terima kasih atas artikel ini, saya kini boleh memberikan anda penyelesaian yang cukup bagus Kodnya ada di bawah:
var vm = require('vm'); var fs = require('fs'); var path = require('path'); /** * Helper for unit testing: * – load module with mocked dependencies * – allow accessing private state of the module * * @param {string} filePath Absolute path to module (file to load) * @param {Object=} mocks Hash of mocked dependencies */ exports.loadModule = function(filePath, mocks) { mocks = mocks || {}; // this is necessary to allow relative path modules within loaded file // i.e. requiring ./some inside file /a/b.js needs to be resolved to /a/some var resolveModule = function(module) { if (module.charAt(0) !== '.') return module; return path.resolve(path.dirname(filePath), module); }; var exports = {}; var context = { require: function(name) { return mocks[name] || require(resolveModule(name)); }, console: console, exports: exports, module: { exports: exports } }; vm.runInNewContext(fs.readFileSync(filePath), context); return context; };
Anda juga boleh memuat turun coretan kod di sini Walaupun kod tersebut paling banyak tidak disiarkan dalam artikel, ia masih boleh menggunakan beberapa penjelasan apabila kami menguji, kami ingin memuatkan modul ini ke dalam ujian , menggunakan theloadModulefunction Memuatkan ujian modul dan bukannya memerlukan.
Parameter pertama, filePath, menentukan lokasi carian di mana kita ingin menguji model. Parameter kedua, mengejek, mengandungi objek yang nama hartanya sepadan dengan nama model yang kami cuba perlukan. Nilai yang ditentukan oleh atribut tersebut ialah objek pseudo, yang digunakan untuk menggantikan model yang diperlukan secara am.
Pada asasnya, ia menggunakan vm untuk memuatkan dan menjalankan model dalam "konteks" lain. Dalam erti kata lain, kami mencipta semula pembolehubah global (seperti keperluan dan eksport) supaya kami boleh mengawalnya. Ambil perhatian bahawa kami telah menulis fungsi memerlukan baharu yang tersedia. Apa yang dilakukannya ialah menyemak untuk melihat sama ada terdapat kebergantungan olok-olok untuk nama pelaksanaan, dan jika ya, saya mewakilkannya kepada fungsi memerlukan biasa.
Contoh penggunaan pemuat modul
Jika anda masih keliru sedikit, anda boleh melihat contoh kod di bawah untuk melihat cara ia digunakan dalam konteks, yang mungkin membantu menjadikannya lebih jelas untuk anda. Pertama, kami membuat modul mudah.
var fs = require('fs'); module.exports = { // Do something with `fs` } 想象一下这个很酷,对吗?不管怎样,现在我们测试那个模块,但是我们要模拟fs来看看它是怎么在内部使用的。 // Jasmine's syntax http://pivotal.github.com/jasmine/ describe('someModule', function() { var loadModule = require('module-loader').loadModule; var module, fsMock; beforeEach(function() { fsMock = { // a mock for `fs` }; // load the module with mock fs instead of real fs module = loadModule('./web-server.js', {fs: fsMock}); }); it('should work', function() { // a test that utilizes the fact that we can now control `fs` }); });
Perkara utama yang perlu diperhatikan ialah pada baris 7 hingga 12, kami mencipta objek tiruan untuk fs dan menggunakan fungsi loadModule baharu kami untuk mengikat objek terpakai ini ke dalam modul kecil di atas (maksud saya hebat! Ingat, yang hebat, betul tak?).