Погружение в автотестирование на iOS. Часть 3. Жизненый цикл iOS приложения во время прогона тестов

от автора

Привет, Хабр!

В этой статье я расскажу про жизненый цикл iOS приложения во время прогона тестов, а в частности про:

  • Предусловия и постусловия в ui-тестах;

  • Запуск/завершение работы приложения;

  • Запуск стороних приложений;

  • Сброс permissions;

  • Определение состояния приложения.

Предусловия и постусловия в ui-тестах

В классе с автотестами мы можем кофигурировать предусловия и постусловия используя следующие методы:

  • Переопределить метод класса setUp(), чтобы установить предусловия для всех тестов в классе(выполняется перед первым тестом в классе);

  • Переопределить метод setUpWithError(), чтобы установить предусловия и обработать ошибки перед запуском каждого теста;

  • Переопределить метод setUp(), чтобы установить предусловия перед запуском каждого теста в классе;

  • Объявить addTearDownBlock(_:) внутри своего тесты, чтобы выполнить очистку необходимых условий в рамках прохождения теста;

  • Переопределить метод tearDown(), чтобы выполнить очистку после каждого теста в клаcсе

  • Переопределить метод tearDownWithError(), чтобы выполнить очистку после каждого теста в клаcсе и обработать ошибки;

  • Переопределить метод класса tearDown(), чтобы выполнить очистку после того как все тесты в классе завершаться.

Пример объявления и использования методов отображен в коде ниже:

//Source: developer.apple.com  class SetUpAndTearDownExampleTestCase: XCTestCase {          override class func setUp() { // 1.         // This is the setUp() class method.         // It is called before the first test method begins.         // Set up any overall initial state here.     }          override func setUpWithError() throws { // 2.         // This is the setUpWithError() instance method.         // It is called before each test method begins.         // Set up any per-test state here.     }          override func setUp() { // 3.         // This is the setUp() instance method.         // It is called before each test method begins.         // Use setUpWithError() to set up any per-test state,         // unless you have legacy tests using setUp().     }          func testMethod1() throws { // 4.         // This is the first test method.         // Your testing code goes here.         addTeardownBlock { // 5.             // Called when testMethod1() ends.         }     }          func testMethod2() throws { // 6.         // This is the second test method.         // Your testing code goes here.         addTeardownBlock { // 7.             // Called when testMethod2() ends.         }         addTeardownBlock { // 8.             // Called when testMethod2() ends.         }     }          override func tearDown() { // 9.         // This is the tearDown() instance method.         // It is called after each test method completes.         // Use tearDownWithError() for any per-test cleanup,         // unless you have legacy tests using tearDown().     }          override func tearDownWithError() throws { // 10.         // This is the tearDownWithError() instance method.         // It is called after each test method completes.         // Perform any per-test cleanup here.     }          override class func tearDown() { // 11.         // This is the tearDown() class method.         // It is called after all test methods complete.         // Perform any overall cleanup here.     }      }

На картинке ниже отображена последовательность выполнения методов:

Запуск/завершение работы приложения

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

// Запускаем приложение XCUIApplication().launch() // Завершаем работу приложения XCUIApplication().terminate()

Если мы хотим запустить приложение с определенными аргументами или переменными окружения, которые были настроены в основном приложении, мы можем запустить приложение с launchArgument или launchEnvironment. Более подробно об аргументах и переменных окружения можно почитать здесь.

let app = XCUIApplication() // Добавляем аргумент для запуска приложения app.launchArguments.append("-debugServer") // Добавляем переменную окружения для запуска приложения app.launchEnvironment = ["inAppPurchasesEnabled":"false",                          "inAppAdsEnabled":"false"] app.launch()

Также это можно сделать через тест-план. Во вкладке Configuration разделе Arguments будут два поля:

  • Arguments Passed on launch — сюда добавляем необходимые аргументы для запуска нужного состояния приложения;

  • Environment variables — сюда добавляем необходимые переменные окружения для запуска нужного состояния приложения.

Более подробно о тест-планах можно прочитать в этой статье.

Запуск стороних приложений

Бывают ситуации, когда нужно запустить стороннее приложение. Например, Safari для проверки диплинков. Это можно сделать в рамках прохождения теста или на старте приложения. Для этого нужно знать bundle id приложения и передать его в качестве аргумента в XCUIApplication.

Информация об доступных bundle id можно найти на сайте apple.

Пример кода для запуска приложения по bundle id:

// Запускаем safari XCUIApplication(bundleIdentifier: "com.apple.mobilesafari").launch()  // Во время прохождения теста открываем safari XCUIApplication(bundleIdentifier: "com.apple.mobilesafari").activate()

Сброс permissions

На WWDC 2020 Apple представили возможность в тестах сбрасывать permissions. Это удобная функция, если вам нужно протестировать разные состояния экрана, завязанные на permissions. Важно, что метод доступен на симуляторах с версией iOS выше или равно 13.4.

Список permissions для сброса, можно посмотреть в перечислении — XCUIProtectedResource:

@available(iOS 13.4, *) public enum XCUIProtectedResource : Int {      // All platforms     case contacts = 1      case calendar = 2      case reminders = 3      case photos = 4      case microphone = 5      case camera = 6      case mediaLibrary = 7      case homeKit = 8           // macOS-specific resources          // iOS Family-specific resources          case bluetooth = -1073741824      case keyboardNetwork = -1073741825      case location = -1073741826 }

Пример как отключить permissions доступа к контактам в рамках теста:

override func setUpWithError() throws {         if #available(iOS 13.4, *) {             application.resetAuthorizationStatus(for: .contacts)         } else {             throw XCTSkip("Required API is not available for this test.")         }     }

В коде выше мы сбрасываем доступ к контактам в предусловии, если симулятор с версией iOS выше или равно 13.4. Если же нет, мы пропускам тест в прогоне.

Состояния приложения

Бывают ситуации, когда нужно понять, в каком состоянии приложение находилось во время прогона тестов.

У приложения есть несколько состояний, которые можно получить во время прохождения теста:

public enum State : UInt {          	case unknown = 0 // Текущее состояние приложения неизвестно  	case notRunning = 1 // Приложение не запущено           	case runningBackgroundSuspended = 2 // Приложение работает в фоновом режиме, но приостановлено           	case runningBackground = 3 // Приложение работает в фоновом режиме  	case runningForeground = 4 // Приложение работает  }

Представим ситуацию, что нам нужно нажать на кнопку home на iPhone 5s и проверить, что приложение перешло в состояние foreground.

Пример реализации такого кейса:

// Нажимаем на текущем симуляторе кнопку home XCUIDevice.shared.press(.home) // Делаем явное ожидания, чтобы состояния приложение обновилось и мы перешли на экран home симулятора Thread.sleep(forTimeInterval: 5) // Проверяем что состояние приложения - runningForeground XCTAssertEqual(XCUIApplication().state, .runningForeground)

Самое важное:

  • Вы можете конфигурировать предусловия и постусловия ваших тестов, используя методы setUp() и tearDown();

  • Запустить приложения, зная его bundle id;

  • Если в приложении есть аргументы или переменные окружения, их можно добавить перед прогоном тестов;

  • Сбрасывать состояния пермишенов вашего приложения можно на симуляторах версии iOS выше или равно 13.4.

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

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

ссылка на оригинал статьи https://habr.com/ru/company/vivid_money/blog/544254/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *