Устранение неудобств разработчиков — iOS Automation | Кодементор

При автоматизации iOS-приложений с помощью Appium команда QA обычно использует xPath чтобы найти элементы пользовательского интерфейса. Но, xPath работает очень медленно и превращает мир автоматизации в ад для работы.

Итак, у нас появилась идея использовать Идентификатор доступности предоставленный фреймворком UIKit, и он отлично работал.

Но теперь проблема в комнате для разработчиков.

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

  • Запросы на слияние будут раздуты сообщениями для добавления Идентификатор доступности всякий раз, когда разработчик пропускает это .
  • Цикл обратной связи между разными командами для отсутствующих/плохих Идентификатор доступности в приоритете.

Мы искали лучшие способы и придумали сумасшедшую идею для создания Идентификатор доступности для каждой переменной автоматически.

Мы рассмотрели Зеркальный API Swift который внутренне использует отражение и нашел способ отразить экземпляр во время выполнения. Зеркальный API очень помогло перебрать все переменные внутри экземпляра.

Но есть одно предостережение. Зеркальный API обеспечивает только для чтения переменные. Итак, нам пришлось использовать UnsafePointer для изменения экземпляра непосредственно на его уровне памяти.

Время посмотреть код.

protocol AccessbilityIdentifierInjector { 
  func injectAccessibilityIdentifiers()
}

Идентификатор ДоступностиИнжектор протокол предоставляет функцию с реализацией по умолчанию для автоматического создания идентификаторов доступа.

extension AccessibilityIdentifierInjector { 
  func injectAccessibilityIdentifiers() { 
    var mirror: Mirror? = Mirror(reflecting: self) 
    repeat { 
      if let mirror = mirror { 
        injectOn(mirror: mirror) 
      } 
      mirror = mirror?.superclassMirror 
    } while (mirror != nil) 
  } 
  
  private func injectOn(mirror: Mirror) { 
    for (name, value) in mirror.children { 
      if var value = value as? UIView { 
        UnsafeMutablePointer(&value).pointee.accessibilityIdentifier = name 
      } 
    }
  }
}

injectAccessibilityIdentifiers() делает две вещи.

  • Итерации, начиная с текущего экземпляра и заканчивая его суперклассом, пока не останется суперкласса.
  • Только фильтры UIView типы и вводить Идентификатор доступности с использованием UnsafePointer объект этой переменной.

Затем нам нужно сделать так, чтобы UIView и UIViewController соответствовали этому протоколу.

extension UIViewController: AccessibilityIdentifierInjector {}  
extension UIView: AccessibilityIdentifierInjector {}

и позвони injectAccessibilityIdentifiers() функция после ее инициализации.

class BaseView: UIView { 
  override init(frame: CGRect) { 
    super.init(frame: frame) 
    injectAccessibilityIdentifiers() 
  }
}

class BaseViewController: UIViewController { 
  override func viewDidLoad() { 
    super.viewDidLoad() 
    injectAccessibilityIdentifiers() 
  }
}

Вот и все. Мы сделали.

Предостережение: Мы не сможем установить идентификатор доступа за ленивый переменные, если они не инициализируются при вызове injectAccessibilityIdentifiers() функция.

Примечание:

  • Наше приложение закрыто для определенной аудитории. У нас нет фактического требования установить идентификаторы доступности. Не рекомендуется, если в вашем приложении настроены имена для идентификаторов доступа.
  • Иногда использование Mirror API может быть медленнее. Если идентификатор доступа не требуется в релизных сборках, мы можем внедрить его только для отладочных/постановочных сборок.

Спасибо.

Похожие записи

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

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