Модульный тест — это код, не являющийся частью целевого приложения. Он предназначен для проверки работоспособности фрагмента целевого приложения.

Например, модульный тест может вызвать какой-нибудь метод из целевого приложения, задать значения его параметров и проверить, всегда ли полученный результат соответствует ожидаемому, т.е. выполнить проверку не только в обычных, но и в неправильных или экстремальных условиях. Модульные тесты полезно разрабатывать до программирования реального кода, рассматривая эту процедуру как часть процесса разработки работоспособного алгоритма. Кроме того, зная, что ваш код уже прошел тестирование, вы можете время от времени повторять его, чтобы убедиться, что не внесли новых ошибок.

 

Модульные тесты не предназначены для проверки работоспособности целевого приложения в целом путем выполнения разнообразных сценариев нажатия кнопок виртуальным пользователем для тестирования интерфейса. Конечно, такую проверку выполнить можно. Например, можно обеспечить доступность вашего приложения, так что элементы пользовательского интерфейса в коде станут видимыми, а затем использовать программу Automation Instrument для выполнения сценариев JavaScript, имитирующих работу виртуального пользователя, но такая проверка не относится к модульному тестированию. Модульные тесты — это инструменты для проверки бизнес-логики, а не интерфейса.

 

В прошлом конфигурирование приложения для модульного тестирования было крайне сложной процедурой, но в среде Xcode 5 модульные тесты стали полноценными компонентами: шаблоны приложений генерируют проекты, имеющие не только целевое приложение, но и цель тестирования (test target), а удобное управление и выполнение тестов обеспечивает как навигатор тестов (<Command+5>), так и файл тестовых файлов.

Тестовый класс в среде Xcode 5 является подклассом класса XCTestCase (который в свою очередь является подклассом класса XCTest). Тестовый метод — это метод экземпляра тестового класса, не возвращающий никаких значений (void) и не имеющий параметров. Его имя начинается со слова test. Тестовая цель зависит от целевого приложения, т.е. до компиляции и сборки тестового класса целевое приложение уже должно быть скомпилировано и собрано. Выполнение теста подразумевает запуск приложения; продуктом тестовой цели является комплект, загружаемый в приложение при его запуске. Каждый тестовый метод будет вызван с одним или несколькими операторами контроля ошибок; в среде Xcode 5 их имена начинаются со слова XCTAssert. (Для того чтобы узнать о них больше, откройте файл XCTestAssertions. h.)

 

Операторы контроля ошибок, имена которых начинаются со слова XCTAssert, на самом деле являются макросами. Не усложняйте их синтаксис, чтобы не создавать проблем. Например, массив литералов, начинающихся с символа здесь не работает.

 

Кроме тестовых методов, тестовый класс может содержать вспомогательные методы, которые вызываются тестовыми методами. Кроме того, они могут содержать любой из четырех специальных методов, унаследованных от класса XCTestCase.

Метод класса setup

Вызывается один раз перед всеми тестовыми методами, содержащимися в классе.

Метод класса setup

Вызывается перед каждым тестовым методом.

Метод класса tearDown

Вызывается после каждого тестового метода.

Метод класса tearDown

Вызывается один раз после всех тестовых методов, содержащихся в классе.

 

Тестовая цель — это разновидность цели, ее продуктом является комплект (bundle), а фазы сборки напоминают фазы сборки целевого приложения. Это значит, что в комплект можно включать ресурсы, такие как тестовые данные. Для загрузки таких ресурсов можно использовать метод setUp; для ссылки на комплект тестирования из кода можно использовать следующее выражение.

 

[NSBundle bundleForClass:[MyTestClass class]]

 

В качестве примера используем проект Empty Window. Включим в класс ViewController (пустой) метод экземпляра dogMyCats:, например:

 - (NSString*) dogMyCats:   (NSString*) cats { return nil; } 

Предполагается, что метод dogMyCats: получает любую строку и возвращает строку @"dogs". Впрочем, сейчас он этого не делает, а вместо этого возвращает значение nil. Это ошибка. Напишем тестовый метод, который будет обнаруживать эту ошибку.

Проект Empty Window содержит один тестовый класс Empty_WindowTests. В отличие от обычного класса, класс Empty_WindowTests объявлен целиком в отдельном файле Empty_WindowTests .m — у него нет соответствующего заголовочного файла (.h), но он содержит разделы @interface и 0implementation в .m-файле. (Как сказано в главе 4, это совершенно законно.)

Удалите из файла Empty_WindowTests .m существующий тестовый метод testExample. Мы заменим его тестовым методом, вызывающим метод dogMyCats: и применяющим оператор контроля ошибок к результату. Поскольку dogMyCats: — это метод экземпляра класса ViewController, нам понадобится экземпляр класса ViewController. Для того чтобы обращаться к экземпляру класса ViewController и вызывать его метод, необходимо импортировать заголовочный файл этого класса:

 

#import "ViewController.h"

 

Мы будем вызывать метод dogMyCats :, чтобы получить возможность пропустить его через компилятор, следовательно, нам нужна информация о методе dogMyCats:. Это значит, что метод dogMyCats: должен быть объявлен в импортированном файле ViewController. h.

Создадим переменную экземпляра в классе Empty_WindowTests для хранения в ней объекта класса ViewController. Объявим свойство в разделе @interface.

 @interface Empty_WindowTests : XCTestCase @property ViewController* ViewController; @end 

Зададим значение этого свойства в методе setup.

 - (void)setUp { [super setUp]; self.ViewController = [ViewController new]; } 

Теперь можно написать тестовый метод. Назовем его testDogMyCats. Он имеет доступ к экземпляру класса через ссылку self .ViewController, потому что метод because setup будет выполнен до тестового метода.

- (void)testDogMyCats {

NSString* input = @"cats";

XCTAssertEqualObjects([self.ViewController dogMyCats:input], @"dogs", @"ViewController dogMyCats: fails to produce dogs from input);

}

Теперь мы готовы выполнить наш тест. Это можно сделать разными способами. Навигатор тестов содержит нашу тестовую цель, тестовый класс и тестовый метод. Наведите курсор мыши на любое из этих имен, и справа от него появится кнопка. Щелкнув на соответствующей кнопке, вы можете выполнить все тесты в каждом классе, все тесты в классе Empty_WindowTests или просто тест testDogMyCats. Однако есть еще кое-что! Вернитесь в файл Empty_WindowTests .m, и вы увидите индикаторы в виде ромбиков на левом поле возле строк, содержащих директиву @interface, и имя тестового метода. Вы можете щелкнуть одном из них, и в результате будут выполнены все тесты в данном классе или отдельный тест соответственно. Кроме того, для того чтобы выполнить все тесты, можно выбрать команду Product^Test.

Проверьте, что во всплывающем меню схемы выбрана цель Simulator, и выполните метод testDogMyCats. Будут последовательно скомпилированы и собраны целевое приложение и целевой тест. (Если хотя бы один из перечисленных этапов не будет выполнен, тестирование невозможно, и вы столкнетесь с хорошо знакомыми ошибками компиляции или сборки.) После этого происходит запуск приложения в окне Simulator и теста.

Тест не выполняется! (Хорошо, мы знали, что это должно случиться, не так ли?) Выполнение приложения в окне Simulator прекращается. Эта ошибка описывается на баннере рядом с оператором контроля ошибок, на котором произошел сбой, а также в навигаторе проблем; возможно, проще всего прочитать о том, что произошло, в навигаторе журнала (в нем есть кнопка More, открывающая полное описание ошибки). Более того, везде появляется красный индикатор X — в навигаторе тестов рядом с методом testDogMyCats, в навигаторе проблем, в навигаторе журнала и в файле Empty WindowTests . m рядом со строкой ©implementation и первой строкой метода testDogMyCats. Большинство из этих индикаторов X являются кнопками! Щелкнув на одной из них, можно выполнить этот тест снова. (После выполнения отдельного теста можно также выбрать команду Products Perform Action^Test [TestMethod] Again.)

Впрочем, все это можно сделать только после того, как мы исправим ошибку в коде. Измените в файле ViewController .m метод dogMyCats, чтобы он возвращал 0"dogs", а не nil. Теперь снова выполните тест. Тест пройден!

Когда возникает сбой теста, вы, возможно, захотите остановить выполнение приложения в той точке, где не выполняется оператор контроля ошибки. Для этого в навигаторе точек прерывания щелкните на кнопке Plus, расположенной внизу, и выберите команду Add Test Failure Breakpoint. Эта точка прерывания напоминает точку прерывания Exception, приостанавливая выполнение приложения на строке, содержащей оператор контроля ошибок в вашем методе, перед тем как выдать сообщение о сбое. После этого можно переключиться на тестируемый метод, например, и проверить его переменные или сделать что-то еще, чтобы устранить причину сбоя.

Существует полезная функциональная возможность, позволяющая перемещаться между методом и тестом, который его вызывает: если выделенная точка находится в методе, меню Related Files в панели быстрого перехода содержит пункт Test Callers. Это же относится к меню Tracking в окне помощника.

Код теста выполняется в комплекте, который по существу включается в выполняемое приложение. Это значит, что он видит глобальные сущности в приложении, например [UIApplication sharedApplication]. Таким образом, например, вместо создания нового экземпляра класса ViewController для инициализации ссылки self .ViewController в классе Empty_WindowTests мы могли бы обращаться к уже существующему экземпляру класса ViewController.

self.ViewController =

( ViewController*)[[[[UIApplication sharedApplication] delegate] window] rootViewController];

Организация тестовых методов в рамках целевых тестов (тестовых наборов) и тестовых классов по большей части является вопросом удобства: она оказывает влияние на макет навигатора тестов и позволяет выделить тесты, выполняемые совместно. Кроме того, каждый тестовый класс имеет свои собственные переменные экземпляра, свой собственный метод setup и т.д. Для того чтобы создать новый целевой тест или новый тестовый класс, необходимо щелкнуть на кнопке Plus в нижней части окна навигатора тестов.

 

Когда вы переименовываете проект, содержащий целевой тест (команда Renaming Parts of a Project), этот целевой тест будет разрушен: некоторые из его настроек сборки по-прежнему ссылаются на старое имя приложения, поэтому целевой тест невозможно собрать и тесты невозможно выполнить. Если вам неудобно редактировать настройки целевого теста вручную, проще всего сделать копию тестового кода, удалить целевой тест, создать новый целевой тест (который уже будет иметь правильные настройки) и восстановить код теста.


 

 

 

Добавить комментарий