Câu trả lời này dựa trên câu trả lời của Andreas Köberle .
Tôi không dễ dàng thực hiện và hiểu giải pháp của anh ấy, vì vậy tôi sẽ giải thích chi tiết hơn về cách thức hoạt động của nó và một số cạm bẫy cần tránh, hy vọng rằng nó sẽ giúp ích cho khách truy cập trong tương lai.
Vì vậy, trước hết là thiết lập:
Tôi đang sử dụng Karma làm người chạy thử và MochaJ làm khung thử nghiệm.
Sử dụng một cái gì đó như Squire không hiệu quả với tôi, vì một số lý do, khi tôi sử dụng nó, khung kiểm tra đã đưa ra các lỗi:
LoạiError: Không thể đọc thuộc tính 'cuộc gọi' không xác định
RequireJs có khả năng ánh xạ id mô-đun sang id mô-đun khác. Nó cũng cho phép tạo một require
chức năng sử dụng một cấu hình khác với toàn cầu require
.
Những tính năng này rất quan trọng để giải pháp này hoạt động.
Đây là phiên bản mã giả của tôi, bao gồm (rất nhiều) ý kiến (tôi hy vọng nó có thể hiểu được). Tôi bọc nó bên trong một mô-đun, để các bài kiểm tra có thể dễ dàng yêu cầu nó.
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;
});
Các cạm bẫy lớn nhất tôi gặp phải, có nghĩa đen chi phí cho tôi giờ, đã tạo ra các RequireJs config. Tôi đã cố gắng (sâu) sao chép nó và chỉ ghi đè các thuộc tính cần thiết (như bối cảnh hoặc bản đồ). Điều này không hoạt động! Chỉ sao chép baseUrl
, điều này hoạt động tốt.
Sử dụng
Để sử dụng nó, yêu cầu nó trong thử nghiệm của bạn, tạo các giả, và sau đó chuyển nó đến createMockRequire
. Ví dụ:
var ModuleMock = function () {
this.method = function () {
methodCalled += 1;
};
};
var mocks = {
"ModuleIdOrPath": ModuleMock
}
var requireMocks = mocker.createMockRequire(mocks);
Và đây là một ví dụ về một tệp thử nghiệm hoàn chỉnh :
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
chức năng. Có một vài lựa chọn khác nhau mặc dù. Tôi sẽ đăng một câu trả lời với hy vọng nó sẽ hữu ích.