The spyOn()
function can only replace object properties, so the only thing you can do is spying on the prototype. Now if you would spy on the prototype of the real class, it would interfere with the other tests, so you have to use prototypal inheritance.
You can do something like this :
var mockClass = function (Subject) {
var Surrogate = function () {
Surrogate.prototype.constructor.apply(this, arguments);
};
Surrogate.prototype = Object.create(Subject.prototype);
Surrogate.prototype.constructor = Subject;
return Surrogate;
};
Some tests:
var My = function (a) {
this.init(a);
};
My.prototype = {
init: function (a) {
this.setA(a);
},
setA: function (a) {
this.a = a;
}
};
var Mock = mockClass(My);
spyOn(Mock.prototype, "constructor").andCallThrough();
spyOn(Mock.prototype, "init");
var m = new Mock(1);
expect(Mock.prototype.init).toBe(m.init);
expect(My.prototype.init).not.toBe(m.init);
expect(m.constructor).toHaveBeenCalledWith(1);
expect(m.init).toHaveBeenCalledWith(1);
expect(m.a).toBeUndefined();
m.setA(1);
expect(m.a).toBe(1);
spyOn(Mock.prototype, "setA").andCallFake(function (a) {
this.a = a + 1;
});
m.setA(1);
expect(m.setA).toHaveBeenCalledWith(1);
expect(m.a).toBe(2);
You cannot spy on the constructor
if your code uses an x.constructor
based type checking. But I think this can happen only by integration tests, and by badly designed codes...