Xcode 7: is chasm between app tests and UI tests unbridgeable?
Asked Answered
C

1

12

Xcode 7† has a new way to test your UI directly, including a new testing target "iOS UI Testing Bundle" (or "OS X").

enter image description here

In the UI testing target, it appears there's no built-in access to the model or classes that comprise your App. E.g. [UIApplication sharedApplication] would not be callable from your UI tests. This implies that "app tests" and "UI tests" exist across a possibly unbridgeable chasm.

As stated here:

The problem is that Xcode’s UI testing does not allow access to the actual app.

Questions:

  1. Can this chasm be bridged? If so, how, in detail, with build and linker settings and possibly a working xcodeproj on github.
  2. Where might a clear statement of this divide to be found, in Apple docs.

† At the time of writing, beta software.

Conall answered 20/7, 2015 at 16:8 Comment(0)
Y
7

Black-box Testing

UI Testing is a black-box testing framework. You shouldn't have to know anything about the implementation of the code you are testing.

For example, you should only care that the value on a label changes, not that the controller passed the right data to the view. You can think of UI Testing from the user of your app's perspective. She doesn't care how your ItemsViewController works (or even that it exists), so why should the UI Tests?

Getting it to "Work"

That being said, I understand your frustration. It would be great if you could spin up a view controller and then tap around with UI Testing and making assertions. However, as of Beta 5 this is not possible.

What's interesting is that you can, however, create instances of your app's objects with a simple @testable import ModuleName at the top of your UI Tests. Note that you can't actually interact with it via the .tap()-like methods, as it's a UI* class, not a XCUI* one.

Consider Donut to be the application's module name.

import XCTest
@testable import Donut

class DonutUITests: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        continueAfterFailure = false
        app.launch()
    }

    func testItemsViewController() {
        let controller = ItemsViewController()
        controller.addItemButton.tap() // <---- UIButton does not respond to tap()!
    }
}
Yorker answered 18/8, 2015 at 15:19 Comment(2)
Let's say you have an app with dynamic content. You want to manipulate the UI and then verify something that isn't visible on-screen. Or, perhaps you need to verify a specified state before deciding which method to call, and that state is only known by querying an Objective-C method in the app code. It's nice to have a mix of both ways of testing, without having to craft each view yourself.Eshelman
Further to Teresa's comments, you might want to initialise your project to a certain state before performing UI tests.Furuncle

© 2022 - 2024 — McMap. All rights reserved.