Я хочу использовать тестирование пользовательского интерфейса для игры, используя SKSpriteKit
.
Поскольку мои первые попытки не сработали, мне интересно, можно ли использовать тестирование пользовательского интерфейса Xcode со SpriteKit.
Я хочу использовать тестирование пользовательского интерфейса для игры, используя SKSpriteKit
.
Поскольку мои первые попытки не сработали, мне интересно, можно ли использовать тестирование пользовательского интерфейса Xcode со SpriteKit.
Основная идея состоит в том, чтобы создать материал доступности для элементов, которые вы хотите протестировать в пользовательском интерфейсе. Это значит:
Список всех доступных элементов, содержащихся в сцене
Настройте параметры для каждого из этих элементов, особенно для frame
data.
Этот ответ предназначен для Swift 3 и в основном основан на Доступность (закадровый голос) с помощью Sprite Kit
Допустим, я хочу сделать кнопку SpriteKit с именем tapMe
доступной.
Добавьте массив UIAccessibilityElement
в сцену.
var accessibleElements: [UIAccessibilityElement] = []
Мне нужно обновить два метода: didMove(to:)
и willMove(from:)
.
override func didMove(to view: SKView) {
isAccessibilityElement = false
tapMe.isAccessibilityElement = true
}
Поскольку сцена является контроллером доступности, в документации указано, что она должна возвращать False
в isAccessibilityElement
.
А также:
override func willMove(from view: SKView) {
accessibleElements.removeAll()
}
Задействовано 3 метода: accessibilityElementCount()
, accessibilityElement(at index:)
и index(ofAccessibilityElement
. Пожалуйста, позвольте мне представить метод initAccessibility()
, который я опишу позже.
override func accessibilityElementCount() -> Int {
initAccessibility()
return accessibleElements.count
}
override func accessibilityElement(at index: Int) -> Any? {
initAccessibility()
if (index < accessibleElements.count) {
return accessibleElements[index]
} else {
return nil
}
}
override func index(ofAccessibilityElement element: Any) -> Int {
initAccessibility()
return accessibleElements.index(of: element as! UIAccessibilityElement)!
}
func initAccessibility() {
if accessibleElements.count == 0 {
// 1.
let elementForTapMe = UIAccessibilityElement(accessibilityContainer: self.view!)
// 2.
var frameForTapMe = tapMe.frame
// From Scene to View
frameForTapMe.origin = (view?.convert(frameForTapMe.origin, from: self))!
// Don't forget origins are different for SpriteKit and UIKit:
// - SpriteKit is bottom/left
// - UIKit is top/left
// y
// ┌────┐ ▲
// │ │ │ x
// ◉────┘ └──▶
//
// x
// ◉────┐ ┌──▶
// │ │ │
// └────┘ y ▼
//
// Thus before the following conversion, origin value indicate the bottom/left edge of the frame.
// We then need to move it to top/left by retrieving the height of the frame.
//
frameForTapMe.origin.y = frameForTapMe.origin.y - frameForTapMe.size.height
// 3.
elementForTapMe.accessibilityLabel = "tap Me"
elementForTapMe.accessibilityFrame = frameForTapMe
elementForTapMe.accessibilityTraits = UIAccessibilityTraitButton
// 4.
accessibleElements.append(elementForTapMe)
}
}
UIAccessibilityElement
для tapMe
frame
находится в верхнем/левом углу UIKit.UIAccessibilityElement
UIAccessibilityElement
в список всех доступных элементов в сцене.Теперь tapMe
доступен с точки зрения тестирования пользовательского интерфейса.
Сессия 406, Тестирование пользовательского интерфейса в Xcode, WWDC 2015
Как обеспечить поддержку VoiceOver в игре SpriteKit? | Форумы разработчиков Apple
swift - Доступность (голос за кадром) с набором Sprite – Qaru
Согласно обсуждению на форуме разработчиков Apple, интеграция UITest со SpriteKit в настоящее время невозможна:
Вероятно, в настоящее время это невозможно, но, вероятно, может быть
Согласно комментарию @ChrisLivdahl, это может быть достигнуто с помощью UIAccessibility — Session 406, Тестирование пользовательского интерфейса в Xcode, WWDC 2015.
Идея состоит в том, чтобы сделать элемент, необходимый для тестирования пользовательского интерфейса.
Я реализовал пример проекта на основе вашего потрясающего ответа (@Domsware) и подтвердил этот трюк хорошо работает как для Xcode UI Платформа тестирования и KIF.
Надеюсь, этот пример поможет всем, кто интересуется этой темой :)
Гораздо более короткое решение, протестированное с SpriteKit, приложением SwiftUI и Swift 5.4
Более ранние подходы больше не работали при использовании XCUI
тестов. Основой моего приложения является приложение SwiftUI, основное представление которого имеет SKScene
. Для того, чтобы это работало, в конце концов, это было довольно просто, и мне потребовалось гораздо меньше шагов для работы.
<сильный>1. Деактивируйте доступность сцены, добавив только одну строку в метод didMove()
override func didMove(to view: SKView) {
isAccessibilityElement = false
}
Как упоминалось в ответе Доминика Виала
<сильный>2. Соответствие ваших узлов протоколу UIAccessibilityIdentification
class YourNode: SKSpriteNode, UIAccessibilityIdentification {
var accessibilityIdentifier: String?
//...
}
Упоминается здесь
Любой узел, который должен быть доступен для теста пользовательского интерфейса, должен соответствовать этому протоколу. Обновите расширение, вместо того, чтобы создавать подклассы для каждого узла, который я сейчас использую, расширение ниже.
<сильный>3. Назначьте accessibilityIdentifier и активируйте доступность объектов ваших узлов.
let yourNode = YourNode()
yourNode.isAccessibilityElement = true
yourNode.accessibilityIdentifier = "nodeID"
<сильный>4. Вот и все! Проведите тесты!
func testingNodes() throws {
app = XCUIApplication()
app.launch()
let node = app.otherElements["nodeID"]
XCTAssert(node.waitForExistence(timeout: 1))
}
<сильный>5. Необязательно: задайте accessibilityTraits
yourNode.accessibilityTraits = [.button, .updatesFrequently]
let nodeAsButton = app.buttons["nodeID"]
Вы можете установить конкретную черту, например .button
, чтобы сообщить API специальных возможностей, какой у вас узел. Это полезно, чтобы лучше различать ваши узлы во время тестирования, а также если вы планируете реализовать фактические функции доступности для пользователя, тогда это должно быть правильно установлено для его работы.
Обновление 1 — Использование расширений:
Вместо того, чтобы создавать подклассы узлов, я использую следующее расширение для SKNode
. Теперь я установил только accessibilityLabel
, а не accessibilityIdentifier
.
extension SKNode: UIAccessibilityIdentification {
public var accessibilityIdentifier: String? {
get {
super.accessibilityLabel
}
set(accessibilityIdentifier) {
super.accessibilityLabel = accessibilityIdentifier
}
}
}
Обновление 2. Доступность всех потомков SKScene
Чтобы узлы и все их потомки были доступны, я использовал следующее расширение на SKNode. Это добавляет каждый узел к accessibilityElements
сцены.
extension SKNode: UIAccessibilityIdentification {
public var accessibilityIdentifier: String? {
get {
super.accessibilityLabel
}
set(accessibilityIdentifier) {
super.accessibilityLabel = accessibilityIdentifier
}
}
func makeUITestAccessible(label: String, traits: UIAccessibilityTraits) {
accessibilityLabel = label
isAccessibilityElement = true
accessibilityTraits = traits
if let scene = scene {
if scene.accessibilityElements == nil {
scene.accessibilityElements = [self]
} else {
scene.accessibilityElements?.append(self)
}
}
}
}