Шпионы
Введение
Что такое шпион для тестирования?
Шпион для тестирования — это функция, которая записывает аргументы, возвращаемое значение, значение 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.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- список значений
thisчерез запятую, с которыми вызывался шпион %n- форматированное значение n-го аргумента, переданного
printf %*- список аргументов (кроме строки формата) через запятую, переданных
printf %D- многострочный список аргументов, полученных при всех вызовах шпиона
© 2010–2018 Christian Johansen
Licensed under the BSD License.
http://sinonjs.org/releases/v5.1.0/spies