Jawaban ini didasarkan pada jawaban Andreas Köberle .
Itu tidak mudah bagi saya untuk menerapkan dan memahami solusinya, jadi saya akan menjelaskannya dengan sedikit lebih detail bagaimana cara kerjanya, dan beberapa jebakan yang harus dihindari, berharap itu akan membantu pengunjung masa depan.
Jadi, pertama-tama pengaturan:
Saya menggunakan Karma sebagai pelari uji dan MochaJs sebagai kerangka uji.
Menggunakan sesuatu seperti Squire tidak berhasil untuk saya, untuk beberapa alasan, ketika saya menggunakannya, kerangka uji melemparkan kesalahan:
TypeError: Tidak dapat membaca properti 'panggilan' yang tidak ditentukan
RequireJs memiliki kemungkinan untuk memetakan id modul ke id modul lainnya. Ini juga memungkinkan untuk membuat require
fungsi yang menggunakan konfigurasi berbeda dari global require
.
Fitur-fitur ini sangat penting untuk solusi ini untuk bekerja.
Ini adalah versi saya dari kode mock, termasuk (banyak) komentar (saya harap ini dapat dimengerti). Saya membungkusnya di dalam modul, sehingga tes dapat dengan mudah membutuhkannya.
define([], function () {
var count = 0;
var requireJsMock= Object.create(null);
requireJsMock.createMockRequire = function (mocks) {
//mocks is an object with the module ids/paths as keys, and the module as value
count++;
var map = {};
//register the mocks with unique names, and create a mapping from the mocked module id to the mock module id
//this will cause RequireJs to load the mock module instead of the real one
for (property in mocks) {
if (mocks.hasOwnProperty(property)) {
var moduleId = property; //the object property is the module id
var module = mocks[property]; //the value is the mock
var stubId = 'stub' + moduleId + count; //create a unique name to register the module
map[moduleId] = stubId; //add to the mapping
//register the mock with the unique id, so that RequireJs can actually call it
define(stubId, function () {
return module;
});
}
}
var defaultContext = requirejs.s.contexts._.config;
var requireMockContext = { baseUrl: defaultContext.baseUrl }; //use the baseUrl of the global RequireJs config, so that it doesn't have to be repeated here
requireMockContext.context = "context_" + count; //use a unique context name, so that the configs dont overlap
//use the mapping for all modules
requireMockContext.map = {
"*": map
};
return require.config(requireMockContext); //create a require function that uses the new config
};
return requireJsMock;
});
Perangkap terbesar yang saya temui, yang benar-benar menghabiskan waktu berjam-jam, adalah menciptakan konfigurasi RequireJs. Saya mencoba (mendalam) menyalinnya, dan hanya menimpa properti yang diperlukan (seperti konteks atau peta). Ini tidak bekerja! Hanya salin baseUrl
, ini berfungsi dengan baik.
Pemakaian
Untuk menggunakannya, minta itu dalam pengujian Anda, buat tiruannya, dan kemudian berikan createMockRequire
. Sebagai contoh:
var ModuleMock = function () {
this.method = function () {
methodCalled += 1;
};
};
var mocks = {
"ModuleIdOrPath": ModuleMock
}
var requireMocks = mocker.createMockRequire(mocks);
Dan di sini contoh file uji lengkap :
define(["chai", "requireJsMock"], function (chai, requireJsMock) {
var expect = chai.expect;
describe("Module", function () {
describe("Method", function () {
it("should work", function () {
return new Promise(function (resolve, reject) {
var handler = { handle: function () { } };
var called = 0;
var moduleBMock = function () {
this.method = function () {
methodCalled += 1;
};
};
var mocks = {
"ModuleBIdOrPath": moduleBMock
}
var requireMocks = requireJsMock.createMockRequire(mocks);
requireMocks(["js/ModuleA"], function (moduleA) {
try {
moduleA.method(); //moduleA should call method of moduleBMock
expect(called).to.equal(1);
resolve();
} catch (e) {
reject(e);
}
});
});
});
});
});
});
define
fungsi. Ada beberapa opsi berbeda. Saya akan mengirim jawaban dengan harapan itu akan membantu.