是否可以使用SpriteKit在应用程序上使用Xcode UI Testing?

时间:2022-11-25 16:54:00

I want to use UI testing for a game using SKSpriteKit.

我想使用SKSpriteKit对游戏进行UI测试。

As my first tries did not work I wonder if it possible to use Xcode UI Testing with SpriteKit.

由于我的第一次尝试不起作用,我想知道是否可以使用SpriteKit进行Xcode UI测试。

3 个解决方案

#1


4  

The main idea is to create the accessibility material for elements that you want to UI test. That's mean:

主要思想是为要进行UI测试的元素创建辅助功能材料。这意味着:

  1. List all accessible elements contained in the scene

    列出场景中包含的所有可访问元素

  2. Configure settings for each of these elements, especially framedata.

    配置每个元素的设置,尤其是framedata。

Step by Step

This answer is for Swift 3 and is mainly based on Accessibility (Voice Over) with Sprite Kit

这个答案适用于Swift 3,主要基于Sprite Kit的辅助功能(Voice Over)

Let's say I want to make the SpriteKit button named tapMe accessible.

假设我想让名为tapMe的SpriteKit按钮可访问。

List of accessible elements.

Add an array of UIAccessibilityElementto the Scene.

将一个UIAccessibilityElement数组添加到Scene中。

 var accessibleElements: [UIAccessibilityElement] = []

Scene's cycle life

I need to update two methods: didMove(to:)and willMove(from:).

我需要更新两个方法:didMove(to :)和willMove(from :)。

override func didMove(to view: SKView) {
    isAccessibilityElement       = false
    tapMe.isAccessibilityElement = true
}

As scene is the accessibility controller, documentation stated it must return False to isAccessibilityElement.

由于scene是辅助功能控制器,因此文档声明必须将False返回给isAccessibilityElement。

And:

override func willMove(from view: SKView) {
    accessibleElements.removeAll()
}

Override UIAccessibilityContainer methods

3 methods are involved: accessibilityElementCount(), accessibilityElement(at index:) and index(ofAccessibilityElement. Please allow me to introduce an initAccessibility() method I'll describe later.

涉及3个方法:accessibilityElementCount(),accessibilityElement(在索引:)和索引(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)!
}

Initialize accessibility for the Scene

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)

    }
}
  1. Create UIAccessibilityElement for tapMe
  2. 为tapMe创建UIAccessibilityElement

  3. Compute frame data on device's coordinates. Don't forget that frame's origin is the top/left corner for UIKit
  4. 计算设备坐标上的帧数据。不要忘记框架的原点是UIKit的左上角

  5. Set data for UIAccessibilityElement
  6. 设置UIAccessibilityElement的数据

  7. Add this UIAccessibilityElement to list of all accessible elements in scene.
  8. 将此UIAccessibilityElement添加到场景中所有可访问元素的列表中。

Now tapMe is accessible from UI testing perspective.

现在可以从UI测试角度访问tapMe。

References

#2


3  

According to Apple developer forum discussion, Integrate UITest with SpriteKit is not currently possible:

根据Apple开发人员论坛的讨论,目前无法使用SpriteKit集成UITest:

This is likely not currently possible, but it probably could be

这可能目前不可能,但可能是这样

Update 2017-02-19

According to comment by @ChrisLivdahl this may be achieved by using UIAccessibility — Session 406, UI Testing in Xcode, WWDC 2015.

根据@ChrisLivdahl的评论,这可以通过使用UIAccessibility - Session 406,Xcode中的UI测试,WWDC 2015来实现。

The idea is to make the element needed UI Testable.

想法是使元素需要UI Testable。

#3


1  

I've implemented an example project based on your (@Domsware's) awesome answer, and I've confirmed this trick works well for both Xcode UI Testing Framework and KIF.

我已经基于您的(@ Domsware)非常棒的答案实现了一个示例项目,并且我已经确认这个技巧适用于Xcode UI Testing Framework和KIF。

Hope this example helps for anyone who is interested in this topic :)

希望这个例子对任何对这个主题感兴趣的人都有帮助:)

#1


4  

The main idea is to create the accessibility material for elements that you want to UI test. That's mean:

主要思想是为要进行UI测试的元素创建辅助功能材料。这意味着:

  1. List all accessible elements contained in the scene

    列出场景中包含的所有可访问元素

  2. Configure settings for each of these elements, especially framedata.

    配置每个元素的设置,尤其是framedata。

Step by Step

This answer is for Swift 3 and is mainly based on Accessibility (Voice Over) with Sprite Kit

这个答案适用于Swift 3,主要基于Sprite Kit的辅助功能(Voice Over)

Let's say I want to make the SpriteKit button named tapMe accessible.

假设我想让名为tapMe的SpriteKit按钮可访问。

List of accessible elements.

Add an array of UIAccessibilityElementto the Scene.

将一个UIAccessibilityElement数组添加到Scene中。

 var accessibleElements: [UIAccessibilityElement] = []

Scene's cycle life

I need to update two methods: didMove(to:)and willMove(from:).

我需要更新两个方法:didMove(to :)和willMove(from :)。

override func didMove(to view: SKView) {
    isAccessibilityElement       = false
    tapMe.isAccessibilityElement = true
}

As scene is the accessibility controller, documentation stated it must return False to isAccessibilityElement.

由于scene是辅助功能控制器,因此文档声明必须将False返回给isAccessibilityElement。

And:

override func willMove(from view: SKView) {
    accessibleElements.removeAll()
}

Override UIAccessibilityContainer methods

3 methods are involved: accessibilityElementCount(), accessibilityElement(at index:) and index(ofAccessibilityElement. Please allow me to introduce an initAccessibility() method I'll describe later.

涉及3个方法:accessibilityElementCount(),accessibilityElement(在索引:)和索引(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)!
}

Initialize accessibility for the Scene

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)

    }
}
  1. Create UIAccessibilityElement for tapMe
  2. 为tapMe创建UIAccessibilityElement

  3. Compute frame data on device's coordinates. Don't forget that frame's origin is the top/left corner for UIKit
  4. 计算设备坐标上的帧数据。不要忘记框架的原点是UIKit的左上角

  5. Set data for UIAccessibilityElement
  6. 设置UIAccessibilityElement的数据

  7. Add this UIAccessibilityElement to list of all accessible elements in scene.
  8. 将此UIAccessibilityElement添加到场景中所有可访问元素的列表中。

Now tapMe is accessible from UI testing perspective.

现在可以从UI测试角度访问tapMe。

References

#2


3  

According to Apple developer forum discussion, Integrate UITest with SpriteKit is not currently possible:

根据Apple开发人员论坛的讨论,目前无法使用SpriteKit集成UITest:

This is likely not currently possible, but it probably could be

这可能目前不可能,但可能是这样

Update 2017-02-19

According to comment by @ChrisLivdahl this may be achieved by using UIAccessibility — Session 406, UI Testing in Xcode, WWDC 2015.

根据@ChrisLivdahl的评论,这可以通过使用UIAccessibility - Session 406,Xcode中的UI测试,WWDC 2015来实现。

The idea is to make the element needed UI Testable.

想法是使元素需要UI Testable。

#3


1  

I've implemented an example project based on your (@Domsware's) awesome answer, and I've confirmed this trick works well for both Xcode UI Testing Framework and KIF.

我已经基于您的(@ Domsware)非常棒的答案实现了一个示例项目,并且我已经确认这个技巧适用于Xcode UI Testing Framework和KIF。

Hope this example helps for anyone who is interested in this topic :)

希望这个例子对任何对这个主题感兴趣的人都有帮助:)