Ускоряем прохождение iOS UI-тестов. Часть 3. Старт приложения с определенного экрана

d0997e116b33b28c4f1df96c75bb3050.jpg

Хабр привет!

Меня зовут Борис. Я руководитель группы автоматизации тестирования в Звук.

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

Данная статья будет полезна iOS-автоматизаторам с опытом, либо разработчикам.

В рамках этой статьи мы разберем:

  • Зачем стартовать приложение с определенного экрана?

  • Какие способы реализации существуют?

  • Реализация с помощью диплинков

  • Реализация с помощью ArgumentHandler для подмены стартового View

  • Плюсы и минусы обоих подходов

Зачем стартовать приложение с определенного экрана?

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

Какие способы реализации существуют?

Принято использовать два подхода:

  1. Реализация с помощью диплинков.

  2. Реализация с помощью ArgumentHandler для подмены стартового View.

Реализация с помощью диплинков

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

  1. Если у вас Xcode версии < 14.3. Данный подход отрабатывает в среднем 7 секунд.

let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
let url = safari.textFields.firstMatch
let alertOpenButton = safari.otherElements["SFDialogView"].buttons.element(boundBy: 1)
safari.activate()
url.waitForExistence(timeout: 2)
url.tap()
url.waitForExistence(timeout: 2)
url.typeText("yourApp://deeplink")
safari.keyboards.buttons["go"].waitForExistence(timeout: 2)
safari.keyboards.buttons["go"].tap()
alertOpenButton.waitForExistence(timeout: 2)
alertOpenButton.tap()

d9225c9fc851e376dcd7ab2606555041.gif

  1. Если у вас Xcode версии > 14.3. Данный подход отрабатывает моментально.

В этой версии Apple добавили метод open(), который позволяет мгновенно открыть диплинк.

XCUIApplication().launch()
let device = XCUIDevice.shared.system
device.open(URL(string: "yourApp://deeplink")!)

fe81fc3b6ce439cd16a94e4a314e7e6d.gif

Плюсы

Минусы

Простая реализация и поддержка

Все экраны должны поддерживать диплинки

Проверка корректности работы диплинков

Реализация с помощью ArgumentHandler для подмены стартового View

Зачастую реализации в проектах бывают более сложными, поэтому данный пример служит ориентиром.

Реализация данного подхода состоит из 3 этапов:

  1. Открыть ваш таргет с ui-тестами и перейти в нужный вам тест. Придумать название для аргумента или переменной, которая бы ассоцировалась с нужным вам экраном или скрином. Как пример название может дублировать название вашего Page в тестах или название ViewController.

// UIKit & SwiftUI
override func setUp() {
	XCUIApplication().launchArguments.append("DetailsScreen")
	XCUIApplication().launchEnvironment["Screen"] = "DetailsScreen"
}
  1. Создать ArgumentHandler в основном таргете приложения.

// UIKit
struct ArgumentHandler {
    static func handleView() -> UIViewController {
        let arguments = ProcessInfo.processInfo.arguments
    
        if arguments.contains("DetailsScreen") {
          return DetailViewController()
        }
        return MainViewController
    }
}
// SwiftUi
struct ArgumentHandler: View {
    var body: some View {
        let arguments = ProcessInfo.processInfo.arguments
        
        if arguments.contains("DetailsScreen"){
            DetailView()
        } else {
            ContentView()
        }
    }
}
  1. Использовать ArgumentHandler для подмены стартового экрана в жизненном цикле приложения. Важно также использовать макрос #DEBUG, чтобы ваша подмена экрана не попала в релизную сборку

// UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
	var window: UIWindow?
	func application(_ application: UIApplication, didFinishLaunchingWithOptions
                     launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

		let window = UIWindow()
		#if DEBUG
		window.rootViewController = ArgumentHandler.handleView()
		#else
		window.rootViewController = MainViewController()
		#endif
		window.makeKeyAndVisible()
	
		self.window = window
		return true
	}
}
// SwiftUI
@main
struct PublicArtApp: App {
	var body: some Scene {
		WindowGroup {
			#if DEBUG
			ArgumentHandler()
			#else
			ContentView()
			#endif
		}
	}
}

Плюсы

Минусы

Экран поднимается моментально

Для реализации нужна помощь разработчика или хороший уровень погружения в проект и разработку

Самое важное

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

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

  • Если у вас в приложении отсутствуют диплинки или они не охватывают основные экраны для тестирования, воспользуйтесь реализацией с использованием ArgumentHandler для подмены стартового View

Навигация по статьям:

Интересуешься автоматизацией на iOS? Подписывайся на мой телеграмм-канал, в котором я публикую материалы, которые будут полезны как начинающим, так и опытным iOS-автоматизаторам.

© Habrahabr.ru