Привет, Хабр!
В прошлой статье мы разобрались:
-
Что такое ui-тесты и для чего они нужны;
-
Как настроить окружение для тестов;
-
Как находить ui-элементы в проекте и проставлять им accessibilityidentifier.
В этой статье мы разберем:
-
Как обращаться и инициализировать ui-элементы в ваших тестах;
-
Как взаимодействовать с ui-элементами приложения;
-
Как писать ассерты для проверки в автотесте ожидаемого результата.
Как обращаться и инициализировать ui-элементы
При наличии айдишника у ui-элемента, достаточно указать его при обращении.
XCUIApplication().buttons["Help"]
Если же у вас нет id у элемента, есть способ найти его при помощи XCUIElementQuery. Этот класс позволяет искать элемент несколькими способами.
// Находит все кнопки внутри scroll view (отобразит кнопки только прямого потомка scroll view)XCUIApplication().scrollViews["Main"].children(matching: .button)// Находит все кнопки внутри scroll view (отобразит кнопки прямого потомка scroll view, но также и его потомков)XCUIApplication().scrollViews["Main"].descendants(matching: .button) // Находит четвертую кнопку на экранеXCUIApplication().buttons.element(boundBy: 3)// Находит в scroll view ui-элемент содержащий label = identifierXCUIApplication().scrollViews["Main"].containing(NSPredicate(format: "label == %@","identifier").element// Находит первую кнопку на экранеXCUIApplication().buttons.firstMatch
Немного про NSPredicate это класс, который позволяет фильтровать объекты по нужному вам условию. Статья с хорошим объяснением как использовать NSPredicate.
Пример иницилизации переменной:
let moneyTitle: XCUIElement = XCUIApplication().staticTexts["accessibilityID"]
Взаимодействия с ui-элементами приложения
Нажатие и удержание
Вы можете в своих тестах совершать: нажатие, удержание и drag&drop ui-элементов.
Перечень методов можно посмотреть здесь, раздел Tapping and Pressing.
// Совершаем нажатие на ui-элементXCUIApplication().buttons.element.tap()// Cовершаем двойное нажатие на ui-элементXCUIApplication().buttons.element.doubleTap()// Удерживаем нажатие в течение времени, которое передали в forDurationXCUIApplication().buttons.element.press(forDuration: 3)// Совершаем нажатие на ui-элемент и затем перетаскиваем его к другому ui-элементуXCUIApplication().buttons.element.press(forDuration: 3, thenDragTo: XCUIApplication().searchFields.element)
Ввод текста
Вы можете вводить текст по букве обращаясь к системной клавиатуре:
XCUIApplication().textFields.element.tap()XCUIApplication().keys["h"].tap()XCUIApplication().keys["e"].tap()XCUIApplication().keys["l"].tap()XCUIApplication().keys["p"].tap()
Либо вводить целую строку:
XCUIApplication().textFields.element.typeText("help")
Множественные нажатия
Вы можете совершать множественные нажатия в своих тестах.
// Совершаем нажатие двумя пальцами на ui-элементXCUIApplication().buttons.element.twoFingerTap()/* Совершаем нажатие на элемент столько раз сколько передали в withNumberOfTaps и столькими "пальцами" сколько передали в numberOfTouches*/XCUIApplication().buttons.element.tap(withNumberOfTaps: 1, numberOfTouches: 1)
Перечень методов можно посмотреть здесь, раздел Multiple Taps.
Жесты
Вы можете совершать разные жесты в своих тестах.
// Совершаем свайп в указанном направленииswipeLeft()swipeRight()swipeUp()swipeDown()// Совершаем свайп в указанном направлении с заданной скоростьюswipeLeft(velocity: 0.5)swipeRight(velocity: 0.5)swipeUp(velocity: 0.5)swipeDown(velocity: 0.5)// Совершаем приближения ui-элемента (withScale указываем больше 1)XCUIApplication().images.element(boundBy: 0).pinch(withScale: 2, velocity: 1) // Совершаем отдаления ui-элемента (withScale указываем от 0 до 1)XCUIApplication().images.element(boundBy: 0).pinch(withScale: 0.5, velocity: 1)// Совершаем вращение ui-элементаXCUIApplication().images.element(boundBy: 0).rotate(0.5, withVelocity: 0.5)
Перечень методов можно посмотреть здесь, раздел Performing Gestures.
Взаимодействие с UISlider
UISlider это элемент управления для выбора одного значения из диапазона значений.
Когда мы хотим изменить положение ползунка в слайдере, мы не передаем значение, которое хотим установить. Вместо этого мы выбираем число в диапазоне от 0 до 1. Где 0 это минимальное значение в слайдере, а 1 максимальное. Представим, что у нас есть слайдер с максимальным значением 100 и нам нужно сдвинуть ползунок на значение 25. Это будет выглядеть так:
XCUIApplication().sliders.element.adjust(toNormalizedSliderPosition: 0.25)
Взаимодействие с UIPickerView и UIDatePicker
UIPickerView и UIDatePicker это ui-элементы, которые используют "колесики" для выбора необходимых значений.
XCUIElement имеет специальный метод для взаимодействия с UIPickerView и UIDatePicker:
-
Для пикеров с одним колесом, мы можем получить доступ через element(), и указать значение, которое хотим выбрать;
-
Для пикеров с несколькими колесами, мы можем обратиться к нужному колесу по индексу и указать значение, которое хотим выбрать.
// Пикер с одним колесомXCUIApplication().pickerWheels.element.adjust(toPickerWheelValue: "BMW")// Пикер с несколькими колесамиXCUIApplication().pickerWheels.elementBoundByIndex(0).adjust(toPickerWheelValue: "BMW")XCUIApplication().pickerWheels.elementBoundByIndex(1).adjust(toPickerWheelValue: "X6")
Взаимодействие с системным алертом
Системный алерт это объект, отображающий предупреждающее сообщение для пользователя.
Чтобы взаимодействовать с ним, вам понадобится использовать метод addUIInterruptionMonitor(withDescription:handler:)
Где вы передаете:
-
withDescription заголовок алерта;
-
handler - действие, которое хотите совершить.
Пример использования в тестах:
addUIInterruptionMonitor(withDescription: "Current Location Not Available") { alert in alert.buttons["OK"].tap() return true}
Взаимодействие с Navigation Bar
Navigation bar это панель навигации, отображается в верхней части экрана приложения под status bar и позволяет перемещаться по приложению.
Представим, что у нас есть две кнопки и текст по середине в Navigation Bar.
Вот пример того как можно их иницилизировать и в дальнейшем с ними взаимодействовать:
// Иницилизируем крайнюю левую кнопку в Navigation bar let leftNavBarButton = XCUIApplication().navigationBars.children(matching: .button).firstMatch// Иницилизируем тест посередине в Navigation bar let topicNavBar = XCUIApplication().navigationBars.children(matching: .staticTexts).firstMatch// Иницилизируем крайнюю правую кнопку в Navigation barlet rightNavBarButton = XCUIApplication().navigationBars.children(matching: .button).element(boundBy: 1)// Нажимаем на кнопки в Navigation bar leftNavBarButton.tap()rightNavBarButton.tap()// Проверяем заголовок в Navigation bar XCTAssertEqual(topicNavBar.title, "Topic")
Взаимодействие с Tab bar
Tab bar это панель вкладок, отображается в нижней части экрана приложения. Она даёт возможность быстро переключаться между различными разделами приложения.
Для переключения между вкладками достаточно тапать на индекс элемента в Tab bar.
// Открываем первую вкладку XCUIApplication().tabBars.buttons.element(boundBy: 0)// Открываем третью вкладкуXCUIApplication().tabBars.buttons.element(boundBy: 2)
Создание ассертов:
Ассерты это проверки необходимого условия.
Рассмотрим несколько вариантов их использования:
// Ассерт, что кнопка отображается на экранеXCTAssertTrue(XCUIApplication().buttons["Warning"].exists)// Ассерт, что кнопка не выделенаXCTAssertFalse(XCUIApplication().buttons["Warning"].isSelected)// Ассерт, что title кнопки равен - BuyXCTAssertEqual(XCUIApplication().buttons.element.title, "Buy")// Ассерт, что placeholder в textFields не равен - placeHolderXCTAssertNotEqual(XCUIApplication().textFields.element.placeholderValue, "placeHolder")// Ассерт, что value в textFields равно - valueXCTAssertEqual(XCUIApplication().textFields.element.value, "value")
Полный перечень возможных ассертов можно посмотреть здесь, раздел Test Assertions
Перечень возможных атрибутов ui-элементов можно посмотреть здесь
Заключение:
Взаимодействовать с ui-элементами во время теста не так сложно, как кажется на первый взгляд. Воспользовавшись примерами выше, можно быстро добавить необходимые методы в свой проект с ui-тестами.
В следующей статье мы расскажем про жизненый цикл тестового приложения:
-
Как делать предусловия и послеусловия;
-
Как сбрасывать статус пермишенов приложения перед запуском тестов (доступ к галерее, фото и так далее);
-
Как запускать приложения по bundle identifier (например запуск сафари, документов и так далее);
-
И многое другое.