Шпионы
Введение
Что такое шпион для тестирования?
Шпион для тестирования — это функция, которая записывает аргументы, возвращаемое значение, значение this и сгенерированное исключение (если таковое имеется) для всех своих вызовов. Существует два типа шпионов: некоторые являются анонимными функциями, а другие оборачивают методы, которые уже существуют в тестируемой системе.
Создание шпиона как анонимной функции
Когда поведение проверяемой функции не находится под тестированием, вы можете использовать анонимный шпион-функцию. Шпион ничего не сделает, кроме записи информации о своих вызовах. Типичный случай использования такого шпиона — тестирование того, как функция обрабатывает обратный вызов, как показано в следующем упрощённом примере:
"test should call subscribers on publish": function () {
var callback = sinon.spy();
PubSub.subscribe("message", callback);
PubSub.publishSync("message");
assertTrue(callback.called);
}
Использование шпиона для обертывания существующего метода
sinon.spy(object, "method") создаёт шпиона, который оборачивает существующую функцию object.method. Шпион будет вести себя точно так же, как и исходный метод (включая использование в качестве конструктора), но у вас будет доступ к данным обо всех вызовах. Ниже приведён немного искусственный пример:
{
setUp: function () {
sinon.spy(jQuery, "ajax");
},
tearDown: function () {
jQuery.ajax.restore(); // Unwraps the spy
},
"test should inspect jQuery.getJSON's usage of jQuery.ajax": function () {
jQuery.getJSON("/some/resource");
assert(jQuery.ajax.calledOnce);
assertEquals("/some/resource", jQuery.ajax.getCall(0).args[0].url);
assertEquals("json", jQuery.ajax.getCall(0).args[0].dataType);
}
}
Создание шпионов: sinon.spy() Подписи методов
var spy = sinon.spy();- Создаёт анонимную функцию, которая записывает аргументы,
thisзначение, исключения и возвращаемые значения для всех вызовов. var spy = sinon.spy(myFunc);- Шпионит за предоставленной функцией
var spy = sinon.spy(object, "method");- Создаёт шпиона для
object.methodи заменяет исходный метод шпионом. Если свойство не является функцией, выбрасывается исключение. Шпион ведет себя точно так же, как и исходный метод во всех случаях. Исходный метод может быть восстановлен, вызвавobject.method.restore(). Возвращаемый шпион — это объект функции, который заменил исходный метод.spy === object.method.
API шпионов
Шпионы предоставляют богатый интерфейс для проверки их использования. Приведённые выше примеры показали calledOnce булево свойство, а также getCall метод и args свойство возвращаемого объекта. Есть три способа проверки данных вызовов.
Предпочтительный подход — использование метода calledWith шпиона (и его аналогов), поскольку это защищает ваш тест от излишней специфичности относительно того, какой вызов что делал и так далее. Он вернёт true , если шпион был вызван с указанными аргументами.
"test should call subscribers with message as first argument" : function () {
var message = 'an example message';
var spy = sinon.spy();
PubSub.subscribe(message, spy);
PubSub.publishSync(message, "some payload");
assert(spy.calledWith(message));
}
Если вам нужна большая специфичность, вы можете напрямую проверить первый аргумент первого вызова. Есть два способа этого добиться:
"test should call subscribers with message as first argument" : function () {
var message = 'an example message';
var spy = sinon.spy();
PubSub.subscribe(message, spy);
PubSub.publishSync(message, "some payload");
assertEquals(message, spy.args[0][0]);
}
"test should call subscribers with message as first argument" : function () {
var message = 'an example message';
var spy = sinon.spy();
PubSub.subscribe(message, spy);
PubSub.publishSync(message, "some payload");
assertEquals(message, spy.getCall(0).args[0]);
}
В первом примере используется двумерный массив args напрямую на шпионе, а во втором примере извлекается объект первого вызова, а затем обращается к массиву args . Какой использовать, дело вкуса, но рекомендуется использовать spy.calledWith(arg1, arg2, ...) , если нет необходимости в высокой специфичности тестов.
API
Объекты шпионов — это объекты, возвращаемые из sinon.spy(). При использовании sinon.spy(object, method) для шпионажа над существующими методами, следующие свойства и методы также доступны для object.method.
Свойства
spy.withArgs(arg1[, arg2, ...]);
Создаёт шпиона, который записывает вызовы только тогда, когда полученные аргументы совпадают с аргументами, переданными в withArgs. Это полезно для выразительных утверждений, где вы можете получить доступ к шпиону с тем же вызовом.
"should call method once with each argument": function () {
var object = { method: function () {} };
var spy = sinon.spy(object, "method");
object.method(42);
object.method(1);
assert(spy.withArgs(42).calledOnce);
assert(spy.withArgs(1).calledOnce);
}
spy.callCount
Количество записанных вызовов.
spy.called
true если шпион был вызван хотя бы один раз
spy.notCalled
true если шпион не был вызван
spy.calledOnce
true если шпион был вызван ровно один раз
spy.calledTwice
true если шпион был вызван ровно дважды
spy.calledThrice
true если шпион был вызван ровно трижды
spy.firstCall
Первый вызов
spy.secondCall
Второй вызов
spy.thirdCall
Третий вызов
spy.lastCall
Последний вызов
spy.calledBefore(anotherSpy);
Возвращает true , если шпион был вызван до anotherSpy
spy.calledAfter(anotherSpy);
Возвращает true , если шпион был вызван после anotherSpy
spy.calledImmediatelyBefore(anotherSpy);
Возвращает true , если spy был вызван до anotherSpy, и между spy и anotherSpy не было вызовов шпионов.
spy.calledImmediatelyAfter(anotherSpy);
Возвращает true , если spy был вызван после anotherSpy, и между anotherSpy и spy не было вызовов шпионов.
spy.calledOn(obj);
Возвращает true , если шпион был вызван хотя бы один раз с obj в качестве this. calledOn также принимает матчер spyCall.calledOn(sinon.match(fn)) (см. матчеры).
spy.alwaysCalledOn(obj);
Возвращает true , если шпион всегда вызывался с obj в качестве this.
spy.calledWith(arg1, arg2, ...);
Возвращает true , если шпион был вызван как минимум один раз с указанными аргументами.
Может использоваться для частичного сопоставления, Sinon проверяет только указанные аргументы по фактическим аргументам, поэтому вызов, получивший указанные аргументы (на тех же позициях) и возможно другие, также вернёт true.
spy.alwaysCalledWith(arg1, arg2, ...);
Возвращает true , если шпион всегда вызывался с указанными аргументами (и возможно другими).
spy.calledWithExactly(arg1, arg2, ...);
Возвращает true , если шпион был вызван как минимум один раз с указанными аргументами и без других.
spy.alwaysCalledWithExactly(arg1, arg2, ...);
Возвращает true , если шпион всегда вызывался с точными указанными аргументами.
spy.calledWithMatch(arg1, arg2, ...);
Возвращает true , если шпион был вызван с сопоставляющимися аргументами (и, возможно, другими).
Это ведет себя так же, как spy.calledWith(sinon.match(arg1), sinon.match(arg2), ...).
spy.alwaysCalledWithMatch(arg1, arg2, ...);
Возвращает true , если шпион всегда вызывался с сопоставляющимися аргументами (и, возможно, другими).
Это ведет себя так же, как spy.alwaysCalledWith(sinon.match(arg1), sinon.match(arg2), ...).
spy.calledWithNew();
Возвращает true , если шпион/заглушка был вызван оператором new.
Обратите внимание, что это выводится на основе значения объекта this и prototype функции шпиона, поэтому это может давать ложные срабатывания, если вы активно возвращаете правильный тип объекта.
spy.neverCalledWith(arg1, arg2, ...);
Возвращает true , если шпион/заглушка никогда не вызывался с указанными аргументами.
spy.neverCalledWithMatch(arg1, arg2, ...);
Возвращает true , если шпион/заглушка никогда не вызывался с сопоставляющимися аргументами.
Это ведет себя так же, как spy.neverCalledWith(sinon.match(arg1), sinon.match(arg2), ...).
spy.threw();
Возвращает true , если шпион бросил исключение как минимум один раз.
spy.threw("TypeError");
Возвращает true , если шпион бросил исключение указанного типа как минимум один раз.
spy.threw(obj);
Возвращает true , если шпион бросил указанный объект исключения как минимум один раз.
spy.alwaysThrew();
Возвращает true , если шпион всегда выбрасывал исключение.
spy.alwaysThrew("TypeError");
Возвращает true , если шпион всегда выбрасывал исключение указанного типа.
spy.alwaysThrew(obj);
Возвращает true , если шпион всегда выбрасывал указанный объект исключения.
spy.returned(obj);
Возвращает true , если шпион вернул указанное значение как минимум один раз.
Использует глубокое сравнение для объектов и массивов. Используйте spy.returned(sinon.match.same(obj)) для строгого сравнения (см. матчеры).
spy.alwaysReturned(obj);
Возвращает true , если шпион всегда возвращал указанное значение.
var spyCall = spy.getCall(n);
Возвращает n-ый вызов.
Доступ к отдельным вызовам помогает с более подробной проверкой поведения, когда шпион вызывается более одного раза.
sinon.spy(jQuery, "ajax");
jQuery.ajax("/stuffs");
var spyCall = jQuery.ajax.getCall(0);
assertEquals("/stuffs", spyCall.args[0]);
var spyCalls = spy.getCalls();
Возвращает Array всех вызовов, записанных шпионом.
spy.thisValues
Массив объектов this, spy.thisValues[0] — это объект this для первого вызова.
spy.args
Массив полученных аргументов, spy.args[0] — массив аргументов, полученных в первом вызове.
spy.exceptions
Массив объектов исключений, spy.exceptions[0] — исключение, сгенерированное первым вызовом.
Если вызов не сгенерировал ошибку, значение в позиции вызова в .exceptions будет `undefined.
spy.returnValues
Массив возвращаемых значений, spy.returnValues[0] — возвращаемое значение первого вызова.
Если вызов явно не вернул значение, значение в позиции вызова в .returnValues будет undefined.
spy.reset()
Сбрасывает состояние шпиона.
spy.restore()
Заменяет шпиона исходным методом. Доступно только если шпион заменил существующий метод.
spy.printf("format string", [arg1, arg2, ...])
Возвращает переданную строку форматирования с выполненными следующими заменами:
%n- имя шпиона по умолчанию "шпион")
%c- количество вызовов шпиона, в словах ("один раз", "дважды" и т. д.)
%C- список строковых представлений вызовов шпиона, каждый вызов с префиксом новой строки и четырьмя пробелами
%t- список значений
thisвызовов шпиона, разделенных запятыми %n- отформатированное значение n-го аргумента, переданного
printf %*- список аргументов (не строковые форматы), переданных
printf, разделенных запятыми
Индивидуальные вызовы шпиона
var spyCall = spy.getCall(n)
Возвращает n-й вызов. Доступ к отдельным вызовам помогает при более детальной проверке поведения, когда шпион вызывается более одного раза.
sinon.spy(jQuery, "ajax");
jQuery.ajax("/stuffs");
var spyCall = jQuery.ajax.getCall(0);
assertEquals("/stuffs", spyCall.args[0]);
spyCall.calledOn(obj);
Возвращает true, если obj был this для этого вызова. calledOn также принимает соответствие spyCall.calledOn(sinon.match(fn)) (см. соответствия).
spyCall.calledWith(arg1, arg2, ...);
Возвращает true, если вызов получил указанные аргументы (и, возможно, другие).
spyCall.calledWithExactly(arg1, arg2, ...);
Возвращает true, если вызов получил указанные аргументы и больше никаких.
spyCall.calledWithMatch(arg1, arg2, ...);
Возвращает true, если вызов получил соответствующие аргументы (и, возможно, другие). Это работает так же, как spyCall.calledWith(sinon.match(arg1), sinon.match(arg2), ...).
spyCall.notCalledWith(arg1, arg2, ...);
Возвращает true, если вызов не получил указанные аргументы.
spyCall.notCalledWithMatch(arg1, arg2, ...);
Возвращает true, если вызов не получил соответствующие аргументы. Это работает так же, как spyCall.notCalledWith(sinon.match(arg1), sinon.match(arg2), ...).
spyCall.threw();
Возвращает true, если вызов бросил исключение.
spyCall.threw("TypeError");
Возвращает true, если вызов бросил исключение указанного типа.
spyCall.threw(obj);
Возвращает true, если вызов бросил указанный объект исключения.
spyCall.thisValue
Значение вызова this.
spyCall.args
Массив полученных аргументов.
spyCall.exception
Брошенное исключение, если есть.
spyCall.returnValue
Возвращаемое значение.
© 2010–2017 Christian Johansen
Licensed under the BSD License.
http://sinonjs.org/releases/v3.3.0/spies