Просто представьте, что вы можете писать сценарии, которые автоматически взаимодействуют с вашим iOS-приложением и могут проверить результаты. С UI Automation вы можете. UI Automation — это инструмент, предоставленный Apple, для проведения более высокого уровня тестирования приложения iOS, превосходящего все, что можно достичь с помощью XCTest.
1. Тестирование белого ящика против черного ящика
Возможно, вы слышали сравнение тестирования белого ящика с тестированием черного ящика в отношении того, как можно протестировать часть программного обеспечения. Если вы не знакомы с этими понятиями, позвольте мне объяснить, как они работают.
Тестирование белого ящика
Представьте, что внутри коробки работает часть программного обеспечения. С помощью тестирования белого ящика вы можете увидеть внутри коробки и посмотреть все мелкие детали работы программного обеспечения, а затем принять обоснованные решения о том, как протестировать программное обеспечение. Вы также можете иметь более глубокие уровни привязки к программному обеспечению из тестов, которые вы пишете.
Модульное тестирование — это тестирование белого ящика. При написании модульных тестов тестер имеет детальный доступ к тестируемому коду. На самом деле тестировщик может написать тесты, использующие тестируемое программное обеспечение на уровне метода или модуля.
В разработке программного обеспечения для iOS мы используем платформу XCTest для выполнения этого типа тестирования. Взгляните на другой урок, который я написал по началу работы с XCTest .
Тестирование черного ящика
При тестировании черного ящика коробка непрозрачна. Тестер не может видеть внутри коробки. Тестер не может получить доступ и не знает о реализации базы кода для написания тестов. Вместо этого тестер вынужден использовать приложение как конечный пользователь, взаимодействуя с приложением и ожидая его ответа, проверяя результаты.
Существует как минимум два способа выполнить этот тип тестирования.
- Тестировщик, который многократно и вручную выполняет ряд заранее определенных шагов и визуально проверяет результаты.
- Используйте специализированные инструменты для тестирования приложения с API, которые ведут себя подобно тому, как взаимодействует человек.
При разработке приложений для iOS Apple предоставляет инструмент под названием UI Automation для тестирования черного ящика.
2. Что такое автоматизация пользовательского интерфейса?
UI Automation — это инструмент, который Apple предоставляет и поддерживает для автоматизированного тестирования приложений iOS на более высоком уровне. Тесты написаны на JavaScript, придерживаясь API, определенного Apple.
Написание тестов можно упростить, полагаясь на метки доступности для элементов пользовательского интерфейса в вашем приложении. Не беспокойтесь, если у вас их нет, есть альтернативы.
В API автоматизации пользовательского интерфейса отсутствует типичный формат xUnit для написания тестов. Одно из отличий модульного тестирования заключается в том, что тестер должен вручную регистрировать успехи и неудачи. Тесты пользовательского интерфейса запускаются из инструмента автоматизации в инструменте инструментов, который поставляется с инструментами разработчика Apple. Тесты можно запустить в iOS Simulator или на физическом устройстве.
3. Написание тестов автоматизации пользовательского интерфейса
Шаг 1: Откройте пример проекта
Я обновил образец проекта, использованного в предыдущем руководстве по тестированию iOS, с некоторыми дополнительными элементами пользовательского интерфейса, которые предоставляют некоторые полезные хуки для добавления тестов автоматизации пользовательского интерфейса. Загрузите проект с GitHub . Откройте проект и запустите приложение, чтобы убедиться, что все работает как положено. Вы должны увидеть пользовательский интерфейс, подобный показанному ниже.
Прежде чем писать какие-либо тесты, не стесняйтесь попробовать пример приложения, чтобы ознакомиться с его функциональностью. Как пользователь, вы можете ввести текст в текстовое поле и нажать кнопку, чтобы увидеть на экране метку, которая отображает обратную введенную строку.
Шаг 2. Создание теста автоматизации пользовательского интерфейса
Теперь, когда вы знакомы с примером приложения, пришло время добавить тест автоматизации пользовательского интерфейса. UI Automation — это инструмент, который можно найти в разделе «Инструменты» . Чтобы запустить образец приложения в Инструментах, выберите Product> Profile из меню Xcode. Выберите Automation из списка инструментов.
Главное окно «Инструменты» откроется с одним готовым к работе инструментом «Инструмент автоматизации» (инструмент автоматизации выполняет контрольные примеры автоматизации пользовательского интерфейса). Вы также увидите область в нижней половине окна, которая выглядит как текстовый редактор. Это редактор скриптов. Здесь вы будете писать свои тесты автоматизации пользовательского интерфейса. Для этого первого теста следуйте приведенным ниже инструкциям, добавляя каждую строку в скрипт в редакторе скриптов.
Начните с сохранения ссылки на текстовое поле в переменной.
1
|
var inputField = target.frontMostApp().mainWindow().textFields()[«Input Field”];
|
Установите значение текстового поля.
1
|
inputField.setValue(«hi”);
|
Убедитесь, что значение было установлено успешно, и, если это так, пройдите тест. Пройдите тест, если это не так.
1
2
|
if (inputField.value() != «hi») UIALogger.logFail(«The Input Field was NOT able to be set with the string!»);
else UIALogger.logPass(«The Input Field was able to be set with the string!»);
|
Хотя этот тест довольно тривиален, он имеет ценность. Мы только что написали тест, который проверяет наличие текстового поля при запуске приложения и проверяет, может ли случайная строка быть установлена в качестве значения текстового поля. Если вы мне не верите, удалите текстовое поле из раскадровки и запустите тест. Вы увидите, что это не удается.
Этот тест демонстрирует три важных части написания тестов автоматизации пользовательского интерфейса. Во-первых, он показывает, как получить доступ к простому элементу пользовательского интерфейса, текстовому полю. В частности, мы получаем доступ к словарю всех текстовых полей в базовом представлении приложения через target.frontMostApp().mainWindow().textFields()
и затем находим интересующее нас текстовое поле, ища поле с ключом Input Field
. Этот ключ фактически является меткой доступности текстового поля. В этом случае это определено в раскадровке. Мы также можем установить метку доступности в коде, используя свойство accessibilityLabel
в NSObject
.
Доступ к главному окну приложения, переднему приложению и цели является обычным явлением при работе с UI Automation. Я покажу вам, как сделать это проще и менее многословным позже в этом уроке.
Во-вторых, это показывает, что вы можете взаимодействовать с элементами пользовательского интерфейса на экране. В этом случае мы устанавливаем значение текстового поля, имитируя пользователя, взаимодействующего с приложением, путем ввода текста в текстовое поле.
И в-третьих, в примере также показан метод проверки того, что происходит в приложении. Если значение успешно установлено, тест проходит. Если значение не установлено, тест не пройден.
Шаг 3: Сохранение тестов
Хотя написание тестов в редакторе сценариев удобно, оно быстро становится громоздким и сложным в обслуживании. Если вы выйдете из Инструментов, все несохраненные изменения будут отменены. Нам нужно сохранить тесты, которые мы пишем. Просто скопируйте и вставьте тест в новый документ в вашем любимом текстовом редакторе и сохраните его. Вы можете найти тесты, созданные в этом руководстве, в примере проекта в Jumblify / JumblifyTests / AutomationTests.js .
Чтобы запустить тест, выберите среднюю вкладку на панели справа рядом с редактором сценариев и выберите « Добавить»> «Импорт» .
Вам будет предложено выбрать скрипт для импорта. Перейдите к сохраненному сценарию и импортируйте его. Вы все еще можете изменить скрипт в редакторе скриптов. Любые изменения будут автоматически сохранены во внешнем файле, который вы создали.
Шаг 4: Нажав кнопку
Давайте обновим наш тест, чтобы проверить взаимодействие с кнопкой. Наш тест уже добавляет текст в текстовое поле, поэтому нам нужно только добавить код, чтобы нажать на кнопку. Давайте сначала рассмотрим, как найти кнопку в представлении, чтобы ее можно было нажать. Есть как минимум три способа сделать это, и у каждого подхода есть свои компромиссы.
Подход 1
Мы можем программно коснуться (X, Y) координаты на экране. Мы делаем это с помощью следующей строки кода:
1
|
target.tap({x: 8.00, y: 50.00});
|
Конечно, я понятия не имею, являются ли они даже координатами кнопки на экране, и я не собираюсь беспокоиться об этом, потому что этот подход не является подходящим инструментом для этой работы. Я только упоминаю это, чтобы вы знали, что это существует. Использование метода tap
к target
при нажатии на кнопку подвержено ошибкам, поскольку эта кнопка не всегда может иметь эту конкретную координату.
Подход 2
Также можно найти кнопку, выполнив поиск по массиву кнопок главного окна, аналогично тому, как мы обращались к текстовому полю в первом тесте. Вместо прямого доступа к кнопке с помощью клавиши, мы можем получить массив кнопок в главном окне и жестко закодировать индекс массива, чтобы получить ссылку на кнопку.
1
|
target.frontMostApp().mainWindow().buttons()[0].tap();
|
Этот подход немного лучше. Мы не жестко кодируем координату, но мы жестко кодируем индекс массива, чтобы найти кнопку. Если мы добавим еще одну кнопку на страницу, это может случайно сломать этот тест.
Подход 3
Это подводит меня к третьему способу поиска кнопки на странице с использованием меток доступности. Используя метку специальных возможностей, мы можем напрямую получить доступ к кнопке, которая нам понравилась, если бы мы нашли объект в словаре, используя ключ.
1
|
target.frontMostApp().mainWindow().buttons()[«Jumblify Button»].tap();
|
Однако, если вы добавите вышеуказанную строку в скрипт и запустите его, вы получите ошибку.
Это потому, что мы еще не определили метку доступности для кнопки. Для этого перейдите в Xcode и откройте раскадровку проекта. Найдите кнопку в представлении и откройте инспектор удостоверений справа (« Просмотр»> «Утилиты»> «Инспектор удостоверений» ). Убедитесь, что Доступность включена, и установите для метки кнопки значение Jumblify Button .
Чтобы снова запустить тест, вам нужно будет запустить приложение из XCode, выбрав « Продукт» > « Выполнить», а затем снова профилировать приложение, выбрав « Продукт» > « Профиль» . Это запускает тесты, и каждый тест должен пройти сейчас.
Шаг 5: Проверьте смешанную строку
Как я упоминал ранее, наше приложение принимает строку текста в качестве ввода и, когда пользователь нажимает кнопку, отображает обратную строку. Нам нужно добавить еще один тест, чтобы убедиться, что входная строка правильно перевернута. Чтобы убедиться, что UILabel
заполнена правильной строкой, нам нужно выяснить, как UILabel
к UILabel
и проверять отображаемую строку. Это общая проблема при написании автоматических тестов, то есть выяснения, как ссылаться на элемент в приложении, чтобы сделать на нем утверждение.
Почти в каждом объекте API автоматизации пользовательского интерфейса есть метод logElementTree
. Этот метод регистрирует вложенные элементы данного элемента. Это очень полезно для понимания иерархии элементов в приложении и помогает выяснить, как настроить таргетинг на конкретный элемент.
Давайте посмотрим, как это работает, зарегистрировав дерево элементов главного окна. Взгляните на следующую строку кода.
1
|
target.frontMostApp().mainWindow().logElementTree();
|
Добавление этой строки в тестовый скрипт приводит к следующему выводу:
Как видите, есть подэлемент UIAWindow
и вы также можете видеть, что у него есть имя ih
, которое также является обратной строкой, которую мы должны проверить. Теперь, чтобы завершить наш тест, нам просто нужно добавить код для доступа к этому элементу и проверить его наличие.
Почему нам нужно только проверить, присутствует ли элемент UIAStaticText
? Поскольку имя элемента является обратной строкой входной строки, проверка его наличия подтверждает правильность обратной строки. Если элемент не существует, когда на него ссылается имя — обратная строка, — это означает, что строка не была правильно обращена.
1
2
3
|
var stringResult = target.frontMostApp().mainWindow().staticTexts()[«ih»];
if (! stringResult.isValid()) UIALogger.logFail(«The output text was NOT set with the correctly reversed string!»);
else UIALogger.logPass(«The output text was set with the correctly reversed string!»);
|
4. Царапин на поверхности
Существует так много других способов, которыми конечный пользователь может взаимодействовать с устройством iOS при использовании вашего приложения. Это означает, что есть много других способов, которыми вы можете использовать UI Automation для симуляции этих взаимодействий. Вместо того, чтобы пытаться собрать полный список этих взаимодействий, я направлю вас к справочной документации по автоматизации пользовательского интерфейса.
Для каждого типа объекта, с которым вы можете взаимодействовать, вы можете просмотреть список методов, доступных для этого объекта. Некоторые методы предназначены для извлечения атрибутов об объекте, а другие — для имитации сенсорного взаимодействия, например flickInsideWithOptions
в UIAWindow
.
Запись сеанса
Когда вы попытаетесь протестировать все более сложные приложения с помощью UI Automation, вы обнаружите, что иногда довольно утомительно многократно использовать logElementTree
чтобы найти logElementTree
элемент. Это также становится утомительным и сложным для приложений со сложной иерархией представлений или навигацией. В этих случаях вы можете использовать другую функцию инструментов для записи набора взаимодействий пользователя. Что еще круче, так это то, что Instruments генерирует код JavaScript UI Automation, необходимый для воспроизведения записанных взаимодействий. Вот как вы можете попробовать это сами.
В разделе «Инструменты» и с выбранным инструментом автоматизации найдите кнопку записи в нижней части окна.
Если вы нажмете кнопку записи, инструменты начнут сеанс записи, как показано на скриншоте ниже.
Инструменты запустят ваше приложение в iOS Simulator, и вы сможете с ним взаимодействовать. Инструменты будут генерировать сценарий на основе ваших взаимодействий в режиме реального времени. Попробуйте. Поворачивайте симулятор iOS, нажимайте в произвольных местах, выполняйте жест смахивания и т. Д. Это действительно полезный способ помочь изучить возможности автоматизации пользовательского интерфейса.
Избегать монолитной кодовой базы
Как вы, вероятно, можете предвидеть, если мы продолжим добавлять тест в файл теста, который мы создали тем же методом, его будет сложно поддерживать. Что мы можем сделать, чтобы этого не случилось. В своих тестах я делаю две вещи, чтобы решить эту проблему:
- Один тест для одной функции: это подразумевает, что тесты, которые мы пишем, должны быть сосредоточены на определенной части функциональности. Я даже дам ему подходящее имя, например
testEmptyInputField
. - Группировка связанных тестов в одном файле: я также группирую связанные тесты в одном файле. Это сохраняет код в одном файле управляемым. Это также облегчает тестирование отдельных частей функциональности, выполняя тесты в определенном файле. Кроме того, вы можете создать мастер-скрипт, в котором вы будете вызывать функции или тесты, сгруппированные в других тестовых файлах.
В следующем фрагменте кода мы импортируем файл JavaScript, и это делает функции этого файла JavaScript доступными для нас.
1
|
#import “OtherTests.js”
|
Вывод
Из этого учебного пособия вы узнали о значении более высокого уровня тестирования и о том, как автоматизация пользовательского интерфейса может помочь восполнить этот пробел. Это еще один инструмент в вашем наборе инструментов, который поможет вам поставлять надежные и надежные приложения.