Создание тестовых объектов с использованием Jasmine 07.05.2016

В прошлой статье мы познакомились с типизацией тестовых объектов, говорили об их назначении и привели несколько соответствующих примеров. Сама задача создания таких объектов не всегда тривиальная и часто требует усилий. Сегодня мы познакомимся с методами создания тестовых объектов Stub и Mock на основе Dummy при помощи библиотеки для тестирования Jasmine.

Снова обратимся к примеру, описанному в статье Dummy, Stub и Mock — создадим тестовые объекты имитирующие поведение объекта-запроса. Немного усложним пример, добавив в сигнатуру метода execute параметр. Для наглядности приведем листинги из данного примера:

interface IRequest {
	execute(query:string):JQueryPromise<void>;
}

class RequestDummy implements IRequest {
	public execute(query:string):JQueryPromise<void> {
		return undefined;
	}
} 

class RequestStub implements IRequest {
	public execute(query:string):JQueryPromise<void> {
		return $.when<void>();
	}
} 

class RequestMock implements IRequest {
	public execute(query:string):JQueryPromise<void> {
		return this.deferred.promise();
	}

	public resolve():void {
		this.deferred.resolve();
	}

	public reject():void {
		this.deferred.reject();
	}

	private deferred:JQueryDeferred<void> = $.Deferred<void>();
}

Рассмотрим способы реализации объектов Mock и Stub при помощи библиотеки Jasmine. Jasmine обладает широкими возможностями для реализации контроля над вызовами методов объектов. Для получения возможности контроля над вызовом конкретного метода объекта достаточно обернуть его в так называемый Spy-объект. Например, получения контроля над вызовом метода execute экземпляра Dummy-запроса request, в тесте нам необходимо выполнить следующий код:

spyOn(request, "execute").and.callThrough();

Обернув метод объектом Spy мы получим возможность сбора статистики вызова метода execute у объекта request, например, вызов request.execute.calls.count() вернет количество вызовов request.execute() с момента создания объекта Spy. Библиотека Jasmine обладает богатым набором функций expect, предназначенных для работы непосредственно с объектами spy. Например, для того, чтобы проверить был ли вызван метод execute c аргументом «test», достаточно следующего вызова:

expect(request.execute).toHaveBeenCalledWith("test");

Подробно об использовании Spy можно прочитать в соответствующем разделе документации на сайте разработчика библиотеки Jasmine.

Для создания сложных тестовых объектов объектов мы воспользуемся возможностью контроля над результатом вызова метода. Результат вызова оборачиваемого метода определяется на момент создания объекта Spy. Например, использованный нами раннее код:

spyOn(request, "execute").and.callThrough();

просто проксирует вызов к реальной реализации метода execute. В случае, если нам требуется контроль над значением, которое должен вернуть execute, нам достаточно создать Spy следующим образом:

spyOn(request, "execute").and.returnValue(request_result);

или

spyOn(request, "execute").and.callFake(() => request_result);

В первом случае все последующие вызовы метода execute будут возвращать значение request_result на момент создания Spy. Во-втором, Jаsmine заменит реальную имплементацию execute вызовом функции, переданной в качестве параметра.
Именно этот функционал нам и необходим для решения нашей задачи.

Для создания stub-запроса нам потребуется просто вернуть разрезолвленный promise:

var request:IRequest = new DummyRequest();
spyOn(request, "execute").and.returnValue($.when<void>());

Для создания mock-запроса — вернуть promise предварительно созданного deferred-объекта:

var request:Request = new DummyRequest(),
	did:JQueryDeferred<void> = $.Deferred<void>();

spyOn(request, "execute").and.returnValue(deferred.promise());

Итак, Spy-объекты библиотеки Jasmine позволяют нам отказаться от необходимости разработки сложных mock-объектов и ограничиться созданием простейших dummy-объектов, реализующих интерфейс реального. Стоит отметить, что Spy может быть создан и на основе реального объекта, однако, в случае, если для его настройки требуется много усилий, это неудобно.

by 07.05.2016