Статьи

Введение в тестирование iOS с помощью автоматизации пользовательского интерфейса

Просто представьте, что вы можете писать сценарии, которые автоматически взаимодействуют с вашим iOS-приложением и могут проверить результаты. С UI Automation вы можете. UI Automation — это инструмент, предоставленный Apple, для проведения более высокого уровня тестирования приложения iOS, превосходящего все, что можно достичь с помощью XCTest.

Возможно, вы слышали сравнение тестирования белого ящика с тестированием черного ящика в отношении того, как можно протестировать часть программного обеспечения. Если вы не знакомы с этими понятиями, позвольте мне объяснить, как они работают.

Представьте, что внутри коробки работает часть программного обеспечения. С помощью тестирования белого ящика вы можете увидеть внутри коробки и посмотреть все мелкие детали работы программного обеспечения, а затем принять обоснованные решения о том, как протестировать программное обеспечение. Вы также можете иметь более глубокие уровни привязки к программному обеспечению из тестов, которые вы пишете.

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

В разработке программного обеспечения для iOS мы используем платформу XCTest для выполнения этого типа тестирования. Взгляните на другой урок, который я написал по началу работы с XCTest .

При тестировании черного ящика коробка непрозрачна. Тестер не может видеть внутри коробки. Тестер не может получить доступ и не знает о реализации базы кода для написания тестов. Вместо этого тестер вынужден использовать приложение как конечный пользователь, взаимодействуя с приложением и ожидая его ответа, проверяя результаты.

Существует как минимум два способа выполнить этот тип тестирования.

  • Тестировщик, который многократно и вручную выполняет ряд заранее определенных шагов и визуально проверяет результаты.
  • Используйте специализированные инструменты для тестирования приложения с API, которые ведут себя подобно тому, как взаимодействует человек.

При разработке приложений для iOS Apple предоставляет инструмент под названием UI Automation для тестирования черного ящика.

UI Automation — это инструмент, который Apple предоставляет и поддерживает для автоматизированного тестирования приложений iOS на более высоком уровне. Тесты написаны на JavaScript, придерживаясь API, определенного Apple.

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

В API автоматизации пользовательского интерфейса отсутствует типичный формат xUnit для написания тестов. Одно из отличий модульного тестирования заключается в том, что тестер должен вручную регистрировать успехи и неудачи. Тесты пользовательского интерфейса запускаются из инструмента автоматизации в инструменте инструментов, который поставляется с инструментами разработчика Apple. Тесты можно запустить в iOS Simulator или на физическом устройстве.

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

Пример приложения

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

Теперь, когда вы знакомы с примером приложения, пришло время добавить тест автоматизации пользовательского интерфейса. 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. Я покажу вам, как сделать это проще и менее многословным позже в этом уроке.

Во-вторых, это показывает, что вы можете взаимодействовать с элементами пользовательского интерфейса на экране. В этом случае мы устанавливаем значение текстового поля, имитируя пользователя, взаимодействующего с приложением, путем ввода текста в текстовое поле.

И в-третьих, в примере также показан метод проверки того, что происходит в приложении. Если значение успешно установлено, тест проходит. Если значение не установлено, тест не пройден.

Хотя написание тестов в редакторе сценариев удобно, оно быстро становится громоздким и сложным в обслуживании. Если вы выйдете из Инструментов, все несохраненные изменения будут отменены. Нам нужно сохранить тесты, которые мы пишем. Просто скопируйте и вставьте тест в новый документ в вашем любимом текстовом редакторе и сохраните его. Вы можете найти тесты, созданные в этом руководстве, в примере проекта в Jumblify / JumblifyTests / AutomationTests.js .

Чтобы запустить тест, выберите среднюю вкладку на панели справа рядом с редактором сценариев и выберите « Добавить»> «Импорт» .

Скриншот инструментов

Вам будет предложено выбрать скрипт для импорта. Перейдите к сохраненному сценарию и импортируйте его. Вы все еще можете изменить скрипт в редакторе скриптов. Любые изменения будут автоматически сохранены во внешнем файле, который вы создали.

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

Мы можем программно коснуться (X, Y) координаты на экране. Мы делаем это с помощью следующей строки кода:

1
target.tap({x: 8.00, y: 50.00});

Конечно, я понятия не имею, являются ли они даже координатами кнопки на экране, и я не собираюсь беспокоиться об этом, потому что этот подход не является подходящим инструментом для этой работы. Я только упоминаю это, чтобы вы знали, что это существует. Использование метода tap к target при нажатии на кнопку подвержено ошибкам, поскольку эта кнопка не всегда может иметь эту конкретную координату.

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

1
target.frontMostApp().mainWindow().buttons()[0].tap();

Этот подход немного лучше. Мы не жестко кодируем координату, но мы жестко кодируем индекс массива, чтобы найти кнопку. Если мы добавим еще одну кнопку на страницу, это может случайно сломать этот тест.

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

1
target.frontMostApp().mainWindow().buttons()[«Jumblify Button»].tap();

Однако, если вы добавите вышеуказанную строку в скрипт и запустите его, вы получите ошибку.

Скриншот сообщения об ошибке инструментов

Это потому, что мы еще не определили метку доступности для кнопки. Для этого перейдите в Xcode и откройте раскадровку проекта. Найдите кнопку в представлении и откройте инспектор удостоверений справа (« Просмотр»> «Утилиты»> «Инспектор удостоверений» ). Убедитесь, что Доступность включена, и установите для метки кнопки значение Jumblify Button .

Скриншот Инспектора Доступности Интерфейсного Разработчика

Чтобы снова запустить тест, вам нужно будет запустить приложение из XCode, выбрав « Продукт» > « Выполнить», а затем снова профилировать приложение, выбрав « Продукт» > « Профиль» . Это запускает тесты, и каждый тест должен пройти сейчас.

Как я упоминал ранее, наше приложение принимает строку текста в качестве ввода и, когда пользователь нажимает кнопку, отображает обратную строку. Нам нужно добавить еще один тест, чтобы убедиться, что входная строка правильно перевернута. Чтобы убедиться, что UILabel заполнена правильной строкой, нам нужно выяснить, как UILabel к UILabel и проверять отображаемую строку. Это общая проблема при написании автоматических тестов, то есть выяснения, как ссылаться на элемент в приложении, чтобы сделать на нем утверждение.

Почти в каждом объекте API автоматизации пользовательского интерфейса есть метод logElementTree . Этот метод регистрирует вложенные элементы данного элемента. Это очень полезно для понимания иерархии элементов в приложении и помогает выяснить, как настроить таргетинг на конкретный элемент.

Давайте посмотрим, как это работает, зарегистрировав дерево элементов главного окна. Взгляните на следующую строку кода.

1
target.frontMostApp().mainWindow().logElementTree();

Добавление этой строки в тестовый скрипт приводит к следующему выводу:

Журнал инструментовElementTree скриншот

Как видите, есть подэлемент 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!»);

Существует так много других способов, которыми конечный пользователь может взаимодействовать с устройством iOS при использовании вашего приложения. Это означает, что есть много других способов, которыми вы можете использовать UI Automation для симуляции этих взаимодействий. Вместо того, чтобы пытаться собрать полный список этих взаимодействий, я направлю вас к справочной документации по автоматизации пользовательского интерфейса.

Для каждого типа объекта, с которым вы можете взаимодействовать, вы можете просмотреть список методов, доступных для этого объекта. Некоторые методы предназначены для извлечения атрибутов об объекте, а другие — для имитации сенсорного взаимодействия, например flickInsideWithOptions в UIAWindow .

Когда вы попытаетесь протестировать все более сложные приложения с помощью UI Automation, вы обнаружите, что иногда довольно утомительно многократно использовать logElementTree чтобы найти logElementTree элемент. Это также становится утомительным и сложным для приложений со сложной иерархией представлений или навигацией. В этих случаях вы можете использовать другую функцию инструментов для записи набора взаимодействий пользователя. Что еще круче, так это то, что Instruments генерирует код JavaScript UI Automation, необходимый для воспроизведения записанных взаимодействий. Вот как вы можете попробовать это сами.

В разделе «Инструменты» и с выбранным инструментом автоматизации найдите кнопку записи в нижней части окна.

Скриншот инструментов, показывающий кнопку записи

Если вы нажмете кнопку записи, инструменты начнут сеанс записи, как показано на скриншоте ниже.

Скриншот инструментов, показывающий процесс захвата

Инструменты запустят ваше приложение в iOS Simulator, и вы сможете с ним взаимодействовать. Инструменты будут генерировать сценарий на основе ваших взаимодействий в режиме реального времени. Попробуйте. Поворачивайте симулятор iOS, нажимайте в произвольных местах, выполняйте жест смахивания и т. Д. Это действительно полезный способ помочь изучить возможности автоматизации пользовательского интерфейса.

Как вы, вероятно, можете предвидеть, если мы продолжим добавлять тест в файл теста, который мы создали тем же методом, его будет сложно поддерживать. Что мы можем сделать, чтобы этого не случилось. В своих тестах я делаю две вещи, чтобы решить эту проблему:

  • Один тест для одной функции: это подразумевает, что тесты, которые мы пишем, должны быть сосредоточены на определенной части функциональности. Я даже дам ему подходящее имя, например testEmptyInputField .
  • Группировка связанных тестов в одном файле: я также группирую связанные тесты в одном файле. Это сохраняет код в одном файле управляемым. Это также облегчает тестирование отдельных частей функциональности, выполняя тесты в определенном файле. Кроме того, вы можете создать мастер-скрипт, в котором вы будете вызывать функции или тесты, сгруппированные в других тестовых файлах.

В следующем фрагменте кода мы импортируем файл JavaScript, и это делает функции этого файла JavaScript доступными для нас.

1
#import “OtherTests.js”

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

Справочник по JavaScript пользовательского интерфейса