Шпионы
Введение
Что такое шпион для тестирования?
Шпион для тестирования — это функция, которая записывает аргументы, возвращаемое значение, значение 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 boolean, а также метод 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");
spy.withArgs(42);
spy.withArgs(1);
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.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/v1.17.7/spies