Как использовать шпионы Jasmine для объекта, созданного внутри другого метода?

Учитывая следующий фрагмент кода, как бы вы создали тест Jasmine spyOn, чтобы подтвердить, что doSomething вызывается, когда вы запустите MyFunction?

function MyFunction() {
    var foo = new MyCoolObject();
    foo.doSomething();
};

Вот как выглядит мой тест. К сожалению, я получаю сообщение об ошибке, когда вычисляется вызов spyOn:

describe("MyFunction", function () {
    it("calls doSomething", function () {

        spyOn(MyCoolObject, "doSomething");
        MyFunction();
        expect(MyCoolObject.doSomething).toHaveBeenCalled();

    });
});

Жасмин, по-видимому, не распознает метод doSomething в этой точке. Любые предложения?

Ответ 1

Когда вы вызываете new MyCoolObject(), вы вызываете функцию MyCoolObject и получаете новый объект с соответствующим прототипом. Это означает, что при spyOn(MyCoolObject, "doSomething") вы не настраиваете шпиона на объект, возвращаемый вызовом new, а на возможную функцию doSomething в самой функции MyCoolObject.

Вы должны иметь возможность сделать что-то вроде:

it("calls doSomething", function() {
  var originalConstructor = MyCoolObject,
      spiedObj;
  spyOn(window, 'MyCoolObject').and.callFake(function() {
    spiedObj = new originalConstructor();
    spyOn(spiedObj, 'doSomething');
    return spiedObj;
  });
  MyFunction();
  expect(spiedObj.doSomething).toHaveBeenCalled();
});

Ответ 2

В качестве альтернативы, как намекал Грегг, мы могли бы работать с 'prototype'. То есть, вместо того, чтобы напрямую следить за MyCoolObject, мы можем отслеживать MyCoolObject.prototype.

describe("MyFunction", function () {
    it("calls doSomething", function () {
        spyOn(MyCoolObject.prototype, "doSomething");
        MyFunction();
        expect(MyCoolObject.prototype.doSomething).toHaveBeenCalled();

    });
});