Шпионы
Введение
Что такое шпион для тестирования?
Шпион для тестирования — это функция, которая записывает аргументы, возвращаемое значение, значение this и исключение, сгенерированное (если таковое имеется) для всех её вызовов. Существует два типа шпионов: некоторые являются анонимными функциями, а другие оборачивают методы, которые уже существуют в системе, подлежащей тестированию.
Создание шпиона как анонимной функции
Когда поведение функции, на которую устанавливается шпион, не тестируется, вы можете использовать шпиона-анонимную функцию. Шпион ничего не сделает, кроме записи информации о своих вызовах. Типичный случай использования этого типа шпиона — тестирование того, как функция обрабатывает обратный вызов, как в следующем упрощенном примере:
Использование шпиона для обертывания всех методов объекта
sinon.spy(object)
Оборачивает все методы объекта.
Обратите внимание, что обычно лучше шпионить за отдельными методами, особенно для объектов, методы которых вы не понимаете или не контролируете (например, зависимости библиотек).
Шпионение за отдельными методами более точно тестирует намерения и менее подвержено непредсказуемому поведению по мере развития кода объекта.
Следующий пример несколько усложнён:
Использование шпиона для обертывания существующего метода
sinon.spy(object, "method") создаёт шпиона, который оборачивает существующую функцию object.method. Шпион будет вести себя точно так же, как исходный метод (включая использование в качестве конструктора), но у вас будет доступ к данным обо всех вызовах. Следующий пример несколько усложнён:
Использование шпиона для обертывания методов получения и задания свойств
sinon.spy(object, "property", ["get", "set"]) создаёт шпионов, которые оборачивают методы получения и задания свойств для object.property. Шпионы будут вести себя точно так же, как исходные методы получения и задания свойств, но у вас будет доступ к данным обо всех вызовах. Пример:
var object = {
get test() {
return this.property;
},
set test(value) {
this.property = value * 2;
}
};
var spy = sinon.spy(object, "test", ["get", "set"]);
object.test = 42;
assert(spy.set.calledOnce);
assert.equals(object.test, 84);
assert(spy.get.calledOnce);
Создание шпионов: 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. var spy = sinon.spy(object, "property", types);- Создаёт шпиона для свойства
object.property, заменяя дескриптор эквивалентным, где каждый указанный аксессор (typesпараметр) обернут в шпион. В отличие от обычных шпионов, возвращаемый объект является дескриптором свойства, содержащим обернутые аксессоры (шпионы). Исходные аксессоры можно восстановить, вызвавspy.get.restore()(гдеget— аксессор, который вы хотите восстановить).
API шпионов
Шпионы предоставляют богатый интерфейс для проверки их использования. В приведенных выше примерах показаны calledOnce булево свойство, а также getCall метод и args свойство возвращаемого объекта. Есть три способа проверки данных вызова вызовов.
Предпочтительный подход — использование метода шпиона calledWith (и его друзей), так как это защищает ваш тест от слишком специфической информации о том, какой вызов что сделал и так далее. Он вернёт true если шпион был когда-либо вызван с указанными аргументами.
Если вам нужно быть более конкретным, вы можете напрямую проверить первый аргумент первого вызова. Есть два способа этого добиться:
Первый пример использует двумерный массив args напрямую со шпионом, в то время как второй пример извлекает объект первого вызова, а затем обращается к массиву args. Какой использовать — вопрос предпочтения, но рекомендуется использовать spy.calledWith(arg1, arg2, ...), если нет необходимости создавать очень специфичные тесты.
API
Объекты шпионов — это объекты, возвращаемые из sinon.spy(). При шпионении за существующими методами с помощью sinon.spy(object, method), следующие свойства и методы также доступны для object.method.
Свойства
spy.withArgs(arg1[, arg2, ...]);
Создаёт шпиона, который записывает вызовы только тогда, когда полученные аргументы соответствуют аргументам, переданным в withArgs. Это полезно для более выразительных утверждений, где вы можете получить доступ к шпиону с тем же вызовом.
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-ый вызов.
Если n отрицательно, возвращается n-ый вызов с конца. Например, spy.getCall(-1) возвращает последний вызов, а spy.getCall(-2) — предпоследний.
Доступ к отдельным вызовам помогает в более подробной проверке поведения, когда шпион вызывается более одного раза.
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–2020 Christian Johansen
Licensed under the BSD License.
https://sinonjs.org/releases/v8.1.1/spies