Шпионы
Введение
Что такое шпион для тестирования?
Шпион для тестирования — это функция, которая записывает аргументы, возвращаемое значение, значение this и выброшенное исключение (если таковое имеется) для всех своих вызовов. Существует два типа шпионов: некоторые являются анонимными функциями, а другие оборачивают методы, которые уже существуют в тестируемой системе.
Создание шпиона как анонимной функции
Когда поведение проверяемой функции не подлежит тестированию, можно использовать шпиона-анонимную функцию. Шпион ничего не сделает, кроме как запишет информацию о своих вызовах. Распространенный случай использования такого шпиона — тестирование того, как функция обрабатывает обратный вызов, как в следующем упрощенном примере:
Использование шпиона для обертывания всех методов объекта
sinon.spy(object)
Оборачивает все методы объекта.
Обратите внимание, что обычно лучше использовать шпиона для отдельных методов, особенно для объектов, которые вы не понимаете или не контролируете все методы (например, зависимости библиотек).
Использование шпионов для отдельных методов позволяет более точно проверить намерения и менее подвержено неожиданному поведению по мере развития кода объекта.
Следующий пример немного искусственный:
Использование шпиона для обертывания существующего метода
sinon.spy(object, "method") создает шпиона, который оборачивает существующую функцию object.method. Шпион будет вести себя точно так же, как оригинальный метод (включая использование в качестве конструктора), но вы получите доступ к данным обо всех вызовах. Следующий пример немного искусственный:
Использование шпиона для обертывания свойств getter и setter
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.withArgs(sinon.match.same(obj)) для строгого сравнения (см. матчинг-функции).
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/v10.0.1/spies