Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can my XCode UI test detect that the screen has changed?

I'm trying to create a tree walker using XCode 7's XCTest UI testing functionality that systematically explores a deterministic tree of table views to a specified depth. It almost works, except that I cannot reliably detect whether or not the tap on any given element has actually triggered a transition to a new screen. I have a hacky method that works most of the time, which is to detect that either the nav bar label has changed OR that the number of menu elements has changed.

The first test has false negatives, because successive screens can have identical nav bar labels (the codebase I'm walking is not mine). The second test has false positives, because sometimes clicking on a table element does not transition to another table/screen but instead adds extra elements to the current screen.

After doing some reading, it seemed that using accessibility labels might be the way to go. So I set a UID for the nav bar's accessibility label in the application code (in viewDidAppear) and then test for it in the UI test code. It feels like this ought to work, but I only ever get back a value of nil in the test code.

I will freely confess that I am a noob when it comes to UI testing and am mainly cutting/pasting/adapting other people's code without having a clear understanding of what I'm doing. So I'm probably making some kind of naive blunder, in the accessibility label code itself and possibly at the conceptual level for detecting that the screen has changed; maybe there's something much simpler/more idiomatic I could be doing.

In the application:

- (void)viewDidAppear: (BOOL)animated {

    [super viewDidAppear: animated];

    //...

    UINavigationBar* navBar = self.navigationController.navigationBar;
    if( navBar )
    {
        static NSInteger s_UID = 0;
        navBar.topItem.accessibilityLabel = [NSString stringWithFormat:@"UID-%ld", s_UID++];
    }
}

In the XCTest UI test:

- (NSString*) navBarAccessibilityLabel: (XCUIApplication*) app
{
    NSString* result = NULL;

    XCUIElementQuery *navBars = app.navigationBars;
    XCUIElement* firstElem = [navBars.staticTexts elementBoundByIndex:0];
    if( firstElem )
    {
        result = (NSString*)firstElem.accessibilityLabel; // This is always nil
    }

    return result;
}

Note that firstElem IS found, and that I am able to extract e.g. firstElem.label from it very happily.

Any help appreciated.

like image 881
Kaitain Avatar asked Dec 16 '15 19:12

Kaitain


People also ask

How do I test UI in Xcode?

How to Run XCUI Tests on XCode. To run the XCUITests on XCode, you can click the highlighted icon below to see your newly created UI Test targets. You can hover on the “testExample()” test case and click the “Play” icon to run that specific test to see if everything was set up properly.

How do I test my iOS UI?

When you're ready to test, go to a test class and place the cursor inside the test method to record the interaction. From the debug bar, click the Record UI Test button. Xcode will launch the app and run it. You can interact with the element on-screen and perform a sequence of interactions for any UI test.

What is Xcuielementquery?

An object that defines the search criteria a test uses to identify UI elements.


1 Answers

You can test if elements are accessible:

Left click inside a UI test and start recording, the simulator will start and you can click on the element inside the simulator, if the element is accessible Xcode will write test code for you inside the testExample method.

enter image description here

Or run your app in the Simulator and open the Accessibility Inspector, and hover over the element as details will appear in the Inspector.

enter image description here

Apart from that, I think in your case you could verify this by adding a navigation item title for each screen i.e. self.navigationItem.title = @"myScreen";

And then verify the screen with an assertion i.e.

// let app = XCUIApplication() // Swift

UIApplication *app = [UIApplication alloc] init]; // Objective-C

XCTAssertEqual(app.navigationBars.element.identifier, "myScreen") // Don't forget to import class XCTest
like image 95
Wojtek Dmyszewicz Avatar answered Sep 21 '22 23:09

Wojtek Dmyszewicz