iOS Development

Testing UIKit accessibility in unit checks – Ole Begemann

Written by admin


I’m writing a customized progress view in UIKit:



My round progress view

One of many design objectives for the view is to be a drop-in substitute for UIProgressView. This implies it ought to mannequin UIProgressView’s API and habits as carefully as doable. One essential side of that is accessibility: ideally, my progress view ought to be indistinguishable from a system progress view to VoiceOver customers.

To this finish, I’d like to jot down a unit check that fails when it finds a discrepancy between my view’s accessibility settings and people of a regular UIProgressView. Earlier than we write that check, although, we should always test what UIProgressView’s accessibility properties truly are to verify we see the right information:

/// Easy checks for the accessibility properties of UIKit controls,
/// to show that the check setup is working.
class UIAccessibilityTests: XCTestCase {
  func testUIProgressViewAccessibility() {
    let progressView = UIProgressView()
    progressView.progress = 0.4

    XCTAssertTrue(progressView.isAccessibilityElement)
    XCTAssertEqual(progressView.accessibilityLabel, "Progress")
    XCTAssertEqual(progressView.accessibilityTraits, [.updatesFrequently])
    XCTAssertEqual(progressView.accessibilityValue, "40%")
    // Extra assertions ...
  }
}

Relying on the atmosphere during which this check is run, some or all of those assertions unexpectedly fail:

  • In a unit check goal for a framework, all assertions fail.
  • In a unit check goal for an iOS utility, solely the primary assertion (isAccessibilityElement) fails, the others cross.

(And sure, I do know a few of the assertions are locale-dependent. In case your check app has localizations for different languages than English, you’ll have to configure the right language in your construct scheme when operating the check.)

Dominik Hauser came upon that we are able to make the primary assertion cross by including the view to a visual window and giving it a non-zero body:

  func testUIProgressViewAccessibility() {
    let progressView = UIProgressView(body: (CGRect(x: 0, y: 0, width: 200, top: 20)))
    progressView.progress = 0.4

    let window = UIWindow(body: CGRect(x: 0, y: 0, width: 400, top: 400))
    window.makeKeyAndVisible()
    window.addSubview(progressView)

    XCTAssertTrue(progressView.isAccessibilityElement)
    XCTAssertEqual(progressView.accessibilityLabel, "Progress")
    /// ...
  }

Thanks quite a bit for the assistance, Dominik (and everybody else who replied to my query)!

To summarize, the necessities for testing UIKit’s accessibility properties in a unit check appear to be:

  1. Your check goal have to be hooked up to an app goal. The checks don’t work in a unit check goal for a library/framework, presumably as a result of making a window seen has no impact when the checks aren’t injected right into a operating app.

  2. Set a non-zero body on the view beneath check.

  3. Create a UIWindow (ideally additionally with a non-zero body, though this wasn’t related in my testing) and add the view to the window. Name window.makeKeyAndVisible.

I say “appear to be” as a result of I’m not sure the habits is 100% deterministic. Some views, like UILabel, don’t require the extra setup.

Extra importantly, I’ve seen my checks fail not less than as soon as. When that occurred, properties like accessibilityLabel didn’t even return their right values when logged to the console from the check app, not simply within the checks. It was as if your complete accessibility system on the simulator was not operating. Attaching the Accessibility Inspector to the simulator as soon as appeared to repair the problem (possibly this induced the accessibility system to restart), and I haven’t been in a position to reproduce the issue since, even after a number of reboots. Every thing seems to be working now.

My check atmosphere: Xcode 11.4.1 with the iOS 13 simulator.



About the author

admin

Leave a Comment