Connect with us

Автоматическое тестирование приложений

Улучшаем предварительные просмотры Xcode с помощью покрытия модульными тестами

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

Опубликовано

/

     
     

В этом году предварительные просмотры Xcode получили большое обновление благодаря новому движку выполнения в Xcode 16. Apple предоставила нам множество новых функций, связанных с предварительным просмотром, таких как поддержка UIKit в макросах #Preview, @Previewable для управления состоянием и PreviewModifier для повторного использования данных. Все это упрощает внедрение предварительных просмотров и повышает популярность разработки с использованием предварительных просмотров.

Однако предварительный просмотр может быть подвержен неожиданным сбоям. Например, кто-то из вашей команды добавляет свойство в представление, использующее @EnvironmentObject. Если он забудет обновить каждый вызов, чтобы установить окружение, приложение упадет. Любой предварительный просмотр, использующий представление без environment, также будет аварийно завершен, когда Xcode попытается отобразить предварительный просмотр. Эта проблема еще более сложная, потому что в Xcode нет встроенного способа проверить, что превью не упадут, без ручного тестирования каждого из них — а это заняло бы невероятно много времени.

Некоторые компании, например Doordash и Handshake, писали о том, как они используют предварительные просмотры для своих снэпшот-тестов — это одна из техник, позволяющих отлавливать неработающие предварительные просмотры. В этом посте мы рассмотрим еще более простой способ — написание юнит-теста, который делает проход по макету всех превью, используя Swift-пакет SnapshotPreviews от Emerge с открытым исходным кодом.

Пример

Рассмотрим эти два представления в разных файлах:

// Title.swift
struct Title: View {
  let title: String
  
  var body: some View {
    Text(title)
      .font(.largeTitle)
  }
}

#Preview {
  Title(title: "Title")
}

// TitleSubtitle.swift
struct TitleSubtitle: View {
  let title: String
  let subtitle: String

  var body: some View {
    HStack {
      Title(title: title)
      Text(subtitle)
    }
  }
}

#Preview {
  TitleSubtitle(title: "Title", subtitle: "subtitle")
}

Теперь вносится изменение, чтобы добавить тему через environment объект в Title.

final class Theme: ObservableObject {
    @Published var textColor: Color = .gray
}

struct Title: View {
  @EnvironmentObject var theme: Theme
  let title: String

    var body: some View {
    Text(title)
      .font(.largeTitle)
      .foregroundStyle(theme.textColor)
  }
}

#Preview {
  Title(title: "Title")
    .environmentObject(Theme()) // crashes without this!
}

Это корректно для превью Title.swift, но вызывает сбой в TitleSubtitle.swift! Это легко исправить, если вы знаете превью, которые в конечном итоге используют Title, но в большой кодовой базе это может быть в файле, который вы даже никогда не видели раньше.

Добавление тестов

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

import SnapshottingTests

// This is an XCTestCase you can run in Xcode
final class MyPreviewTest: PreviewLayoutTest { }

Тестовые функции будут автоматически добавлены для каждого предварительного просмотра в приложении. Вы можете легко просмотреть результаты в Xcode или автоматизировать их запуск в рамках CI с помощью Fastlane или xcodebuild.

Успешный результат будет выглядеть следующим образом:

Улучшаем предварительные просмотры Xcode с помощью покрытия модульными тестами

И предыдущий пример приведут к аварийному завершению работы с указанием проблемы в стек-трейсе:

Улучшаем предварительные просмотры Xcode с помощью покрытия модульными тестами

Как это работает

Это работает путем чтения метаданных типов Swift в бинарном файле приложения, чтобы найти все записи о соответствии протоколу PreviewProvider. Соответствующие типы динамически инициализируются и вызываются для получения представления SwiftUI для каждого провайдера. Затем представления декомпозируется на превью с помощью VariadicView.

Благодаря динамической природе среды выполнения Objective-C, для каждого обнаруженного превью в тестовый класс добавляется новая тестовая функция. Поскольку все это происходит автоматически, вам не нужно писать никакого кода, просто добавьте новые превью в ваше приложение, и оно будет протестировано!

Заключительные мысли

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

Источник

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.

Наши партнеры:

LEGALBET

Мобильные приложения для ставок на спорт
Хорошие новости

Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: