Модульные тесты Jasmine неожиданны для этой ссылки

Я пытаюсь протестировать довольно простую функцию JavaScript в Jasmine, однако первый оператор выдает ошибку из-за того, что он не определен.

myClass.prototype.functiontoBeTested = function() {
var x = this.method()
...
}

Вышеприведенное выдает ошибку в Jasmine, поскольку method не является функцией и не определено. Прототип изменен ранее, чтобы иметь этот метод, и из любопытства я назначил этот метод моему тестовому объекту в самой спецификации как таковой:

myObject.method = function(){return mockResults;};

Поэтому я решил вывести this в консоль, и вместо того, чтобы быть моим объектом, я вижу Window {top: Window, location: Location, document: document, window: Window, external: Object…}, что кажется неправильным. У меня была эта проблема раньше при тестировании функции в Jasmine, которая использовала this, но просто изменила исходный код, чтобы ссылаться на объект по имени, поскольку функция была назначена чему-то внутри замыкания. В данном случае я не могу этого сделать, и мне любопытно, почему this имеет в виду что-то неожиданное (по крайней мере, для меня).

Изменить: некоторые подробности о том, как выглядит тестовый пример в соответствии с запросом:

it("updates the control count", function(){
    var mockResults = { ... };
    myObject.method = function() {return mockResults;};
    expect(myObject.method).not.toThrow();
});

Сейчас я просто пытаюсь заставить метод выполняться до завершения во время теста. Тестируемая функция обновляет текст в некоторых компонентах HTML, я буду работать над их проверкой, как только смогу заставить ее работать. Метод, вызывающий ошибку, находится в первой строке функции и является просто методом доступа к вызываемому объекту. В реальном исполнении var x = this.method() работает без проблем. При тестировании в jasmine var x = this.method() выдает ошибку, потому что method() не определено для this. Вместо того, чтобы this ссылаться на вызывающий объект, он ссылается на окно. Это происходит не вживую, а только во время тестирования с Жасмин. Этот метод не определен, даже если я принудительно определяю его для тестового объекта непосредственно перед выполнением в тесте, как указано выше. Именно тогда я решил записать this в консоль в исходном коде и понял, что это не относится к тому, на что я ожидал.


person Michael    schedule 11.06.2015    source источник
comment
Не могли бы вы опубликовать код, как вы тестируете свой класс?   -  person Michael Radionov    schedule 12.06.2015
comment
Конечно, я добавлю это к исходному вопросу.   -  person Michael    schedule 12.06.2015
comment
Вот как я вижу, как это должно работать plnkr.co/edit/wYhw9d0PdtppLrsbZqQb?p=preview из описания. Есть ли какие-то особые отличия по сравнению с вашим исходным тестом?   -  person Michael Radionov    schedule 12.06.2015
comment
Вот как я ожидаю, что это сработает, я просто хочу уточнить, что я только издеваюсь над методом как этапом устранения неполадок в тесте. Я бы предпочел не переопределять его в своем тестовом примере. Ваш пример Plunker — это, по сути, то, что происходит в моем коде, за исключением того, что тестируемая функция выдает ошибку, поскольку метод не определен для this во время выполнения.   -  person Michael    schedule 12.06.2015
comment
@JamesThorpe Ваш заказ, вероятно, имеет больше смысла, но у него все еще была проблема с выходом undefined. То, что опубликовал Михаил Радинов, решило проблему для меня. Я думаю, что главный урок здесь для меня заключается в том, что я не должен так сильно полагаться на toThrow для своих модульных тестов.   -  person Michael    schedule 12.06.2015


Ответы (1)


В JavaScript this для метода зависит от контекста, из которого он был вызван. Когда вы делаете вызов myObject.method(), то method вызывается из контекста myObject, поэтому this равно myObject.

Когда вы передаете свою функцию сопоставителю Jasmine toThrow, он вызывает ее так, как она была передана (см. исходный код):

try {
    actual();
} catch (e) {
   // ....
}

Здесь actual() — это вызов вашего метода. У него нет определенного контекста, поэтому по умолчанию он будет вызываться из контекста window.

Решение состоит в том, чтобы явно привязать вас method к myObject вот так:

expect(myObject.method.bind(myObject)).not.toThrow();

Кредиты на вопросы, вы можете найти более подробную информацию здесь:

person Michael Radionov    schedule 12.06.2015
comment
Это было так, спасибо. Я собираюсь добавить это в вики моей команды для модульного тестирования с Жасмин, я сомневаюсь, что я буду единственным человеком, который когда-либо попадется на это. - person Michael; 12.06.2015