Статьи
Активности и Вложения в XCTest
Это позволяет нам делать много интересных вещей.
Сегодня продолжим тему тестирования и расскажу про еще одну замечательную фичу фреймворка XCTest. Я люблю UI-тестирование и защиту основных пользовательских потоков в моем приложении. Мы поговорим о скрытых жемчужинах фреймворка XCTest, которыми являются Активности (Activity) и Вложения (Attachments).
Активности
Давайте начнем с понятия активности в XCTest. Когда вы запускаете UI-тест в разделе Report в Xcode, вы можете найти лог каждого действия, которое вы выполняете в данном UI-тесте.
final class UITests: XCTestCase {
var app: XCUIApplication!
override func setUp() {
continueAfterFailure = false
app = XCUIApplication()
app.launch()
}
func testFoodLoggingFlow() {
goToSearch()
search(query: «Pasta»)
chooseFirstFoodItem()
logSelectedFood()
}
}
Прекрасно, что Xcode протоколирует каждое действие, и мы можем просмотреть их позже, но трудно здесь понять, что есть что. И для этого конкретного случая мы можем использовать активности XCTest. Активность XCTest позволяет нам сгруппировать и назвать набор действий внутри теста. Давайте посмотрим, как мы можем использовать этот API.
final class UITests: XCTestCase { var app: XCUIApplication! override func setUp() { continueAfterFailure = false app = XCUIApplication() app.launch() } func testFoodLoggingFlow() { XCTContext.runActivity(named: "Search") { _ in goToSearch() search(query: "Pasta") } XCTContext.runActivity(named: "Saving") { _ in chooseFirstFoodItem() logSelectedFood() } } }
Как видно из приведенного примера, мы используем функцию runActivity для типа XCTContext. Эта функция принимает два параметра: имя активности и closure, определяющее действие. Это позволяет нам легко группировать и присваивать имена действиям в тесте и гораздо проще просматривать их в навигаторе отчетов.
Вложения
Второй замечательной особенностью фреймворка XCTest является концепция вложений. Вы можете добавлять вложения к любому тестовому случаю или активности. Например, это может быть скриншот текущего состояния вашего приложения при выполнении определенного действия. Давайте посмотрим, как мы можем использовать активность XCTest для добавления скриншотов.
protocol Screen { var app: XCUIApplication { get } } extension Screen { func takeScreenshot() { XCTContext.runActivity(named: "Screenshot") { activity in let screenshot = app.screenshot() let attachment = XCTAttachment(screenshot: screenshot) attachment.lifetime = .keepAlways activity.add(attachment) } } }
Как видно из примера выше, мы используем XCTContext для запуска активности и используем функцию add для типа XCTActivity, чтобы прикрепить скриншот. Тип XCTAttachment позволяет нам прикреплять скриншоты, любые экземпляры типов String и Data или содержимое файла.
struct FeedScreen: Screen { let app: XCUIApplication func goToSearch() -> SearchScreen { app.buttons["Add"].firstMatch.tap() XCTAssertTrue(app.buttons["Search"].waitForExistence(timeout: 3)) app.buttons["Search"].tap() XCTAssertTrue(app.navigationBars.staticTexts["Search"].waitForExistence(timeout: 3)) takeScreenshot() return SearchScreen(app: app) } } struct SearchScreen: Screen { let app: XCUIApplication func search(query: String) -> Self { app.searchFields.firstMatch.tap() app.searchFields.firstMatch.typeText("pasta") takeScreenshot() return self } func verifyResults(contain text: String) -> Self { let cell = app.collectionViews.cells.element(boundBy: 0) XCTAssertTrue(cell.waitForExistence(timeout: 3)) XCTAssertTrue(cell.accessibilityValue?.contains(text) ?? false) return self } }
Я большой поклонник паттерна Page Object и делаю свой набор тестов пользовательского интерфейса на его основе. Я определяю протокол Screen, которому соответствует каждый объект Page Object в моем приложении. Он содержит множество полезных функций, одной из которых является функция takeScreenshot (чтобы узнать о паттерне Page Object, который я использовал в приведенном выше примере, ознакомьтесь с моей статьей «UI-тестирование с помощью паттерна Page Object в Swift«).
import XCTest final class UITests: XCTestCase { var app: XCUIApplication! override func setUp() { continueAfterFailure = false app = XCUIApplication() app.launch() } func testSearchFlow() { FeedScreen(app: app) .goToSearch() .search(query: "Pasta") .verifyResults(contain: "PASTA") } }
И, наконец, мы можем просмотреть и сохранить все эти вложения в разделе Report в Xcode. Это позволяет нам делать много интересных вещей. Например, можно запустить набор UI-тестов, которые проходят через основные потоки вашего приложения и собирают скриншоты для страницы App Store. Можно запустить его под разными локалями, чтобы автоматизировать сбор скриншотов приложения.
Надеюсь, вам понравится этот пост. Не стесняйтесь следить за мной в Twitter и задавать свои вопросы, связанные с этим постом. Спасибо, что прочитали, и до встречи на следующей неделе!