Шпионы
Введение
Что такое шпион для тестирования?
Шпион для тестирования — это функция, которая записывает аргументы, возвращаемое значение, значение 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");
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.calledOnceWith(arg1, arg2, ...);
Возвращает true если шпион был вызван ровно один раз с предоставленными аргументами.
spy.alwaysCalledWith(arg1, arg2, ...);
Возвращает true если шпион всегда вызывался с предоставленными аргументами (и, возможно, другими).
spy.calledWithExactly(arg1, arg2, ...);
Возвращает true если шпион был вызван по крайней мере один раз с указанными аргументами и без других.
spy.calledOnceWithExactly(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.resetHistory();
Сбрасывает состояние шпиона.
spy.restore();
Заменяет шпиона оригинальным методом. Доступно только если шпион заменял существующий метод.
spy.printf("format string", [arg1, arg2, ...]);
Возвращает переданную строку формата с выполненными заменами:
%n- имя шпиона ("шпион" по умолчанию)
%c- количество вызовов шпиона, в словах ("один раз", "дважды" и т.д.)
%C- список строковых представлений вызовов шпиона, каждый с префиксом новой строки и четырьмя пробелами
%t- список аргументов, переданных в вызов шпиона, разделённых запятыми
%n- форматированное значение n-го аргумента, переданного в
printf %*- список аргументов (не строки формата), переданных в
printf %D- многострочный список аргументов, полученных всеми вызовами шпиона
© 2010–2018 Christian Johansen
Licensed under the BSD License.
https://sinonjs.org/releases/v6.3.5/spies