Xcode UI Test example - ios

I have just recently learned about Unit Testing in Xcode. Now I am trying out Xcode 7 and I see there is a new group for UI Tests when I create a new project.
I watched the WWDC 2015 video and it was pretty good, but do you have a super simple example that I could go through myself? The video examples were a little too complex for me.
Notes
The answer below is my attempt to figure this out, but I welcome any better answers.
I have read these SO questions about UI Testing in Xcode but they are different: docs, reloading, App vs UI, ViewController, multiple, values and properties, pre XCode 7 projects.

Use Unit Tests to test the validity of methods in your classes. You use them to test the code you have written. (See my other example for setting up a simple Unit Test in Xcode.)
Use UI Tests to check the validity of the User Interface. Think of it like having your own robot to go through and do all the normal interactions with your app that a normal user would. This saves you the time of doing it yourself.
At the time of this writing, it is difficult to access many of the properties of the UI components, but just having a test go through tapping them and swiping them confirms that they are there.
Example
This is about the simplest setup and UI test that I could think of: a button that when pressed changes the text of a label.
Set up
Create a new project in Xcode 7+ for iOS 9.0+.
Make sure that Include UI Tests is checked
If you are adding UI tests to a project created before Xcode 7, see this answer. (File > New > Target > Test > Cocoa Touch UI Testing Bundle)
Add a UILabel and a UIButton to the storyboard
Create an #IBOutlet and #IBAction in the ViewController and make the label text change when the button is pressed.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBAction func button(sender: AnyObject) {
label.text = "Hello"
}
}
Do the test
Open the YourProjectUITests file.
Put your curser in the testExample() method. (You can delete the comments)
Press the red Record button
In the app, (1) tap the label, (2) tap the button, and then (3) tap the label again. (4) Press the Record button again to stop recording. The following code should have been automatically generated for you:
func testExample() {
let app = XCUIApplication()
app.staticTexts["Label"].tap()
app.buttons["Button"].tap()
app.staticTexts["Hello"].tap()
}
Use the staticText lines as a starting point for making an XCTAssert. Now you should have:
func testExample() {
let app = XCUIApplication()
XCTAssert(app.staticTexts["Label"].exists)
app.buttons["Button"].tap()
XCTAssert(app.staticTexts["Hello"].exists)
}
Press the diamond on the left to run the UI Test. It should turn green when it passes.
That's it! This showed that the UIButton and UILabel exist and that the text of the label changed. If you want to see it fail (a good idea), you can change "Hello" to something else.
Further study
UI Testing in Xcode
Exploring the New UI Testing Features of Xcode 7
Xcode 7 UI testing, a first look
UI Testing in Xcode 7

#Suragch +1 for the answer. One thing I observed and want to share that every function inside the UI Test case must start with "test". You can append extra name after that. Only this way the button(for clicking to start the test) appears.

Related

What is the reset(_:) method

I am learning iOS app development, and I came across a line which confused me:
Also add a call from reset(_:) so it works when you reset the app
But I can't find a reset(_:) function anywhere, both in ViewController and AppDelegate. Do I have to create the function, or is it something different?
So let's add the additional infos:
Your quote is from Intro to App Development with Swift, Apple's iBook., chapter 17.6 Polishing the Interface, in Disabling sliders subpart.
You missed the previous part:
#IBAction func reset(_ sender: AnyObject) {​} Open the Connections inspector. You’ll see that the button has been
connected to the Touch Up Inside event. This is the standard event
used ​for most buttons. Your reset button will set the value of each
slider to 1 and the isOn property of each switch to false. Add that
code to the new action method.
So your quote was talking about that method that you should have added previously on ViewController.swift in the chapter 17.5 Reset Button.

Cannot see recording red button for XCUITest in Xcode 9.2

As I am new to XCUITest, I want to write a test case by recording actions in the simulator but can't see the recording button in XCTestCase class.
What is the process to record a test case?
This might seem trivial, but almost drove me mad when I started with XCUITesting:
Notice that your cursor must be inside a function starting with test:
This won't work, though (Record button is greyed out):
I think that if you are not seeing the record button is because you don't have a iOS UI Testing Bundle in your targets. To do this you need to go to your project file and click the "+" button down on targets and then you add an iOS UI Testing Bundle. Then you will see a new folder named as your new target. There you can add UI tests and record them.

In Xcode 8.2.1 I am unable to link #IBOutlet to the UI

I am having a huge problem when I follow this very simple procedure:
Create a new project
Add a label to the UI
Add '#IBOutlet var testLabel:UILabel!' to ViewController.swift
Open side-by-side editor
Drag from #IBOutlet to the label in the storyboard
At this point you should see two options in the semi-transparent window, testLabel and view however all I see is 'view'.
I recently updated Xcode from the app store and this is when the behavior started. I tried on an older machine with Xcode 7 and the procedure is sound, Xcode 7 detects the Outlet.
Am I missing something here? I tried installing 8.2.1 on a third machine and I am having the same exact problem.
Whenever you get flaky Xcode behavior, it is prudent to empty the "derived data" folder:
locate the derived data folder (it can be found under "Preferences" on "Xcode" menu and then choose the "Locations" tab);
quit Xcode;
empty the derived data folder; and
restart Xcode.
If that doesn't do it, sometimes repeating the process but rebooting before restarting Xcode will do it too.
For what it's worth, while can't reproduce your specific problem, I do experience a related problem that if I manually write an #IBAction and then drag from an event for a button (e.g. "Touch up inside"), it won't always recognize my #IBAction. But if I drag to an empty portion of my code, and let IB create its own #IBAction and give it a name (which can be identical to my manually written #IBAction) and then delete it's templated #IBAction, it then recognizes mine, fine. There's definitely a little flakiness in this connection process.

I'm getting a lock alert when trying to connect/add elements to the viewcontroller in Xcode 7.3

I have a ViewController that all of the sudden will not allow me to add a new element or connect an existing element to an IBAction. I've looked through sample code as well and googled the s*%& out of it without finding a solution.
My ViewController.swift file contains this code:
#IBAction func helpButtonTapped(sender: AnyObject) {
}
And I'm trying to connect a very basic button.
Also, note that I've double-checked to be sure that all elements and views are set to Lock: Nothing.
Any help would be amazing!
Go to menu Editor then Localization Locking then choose Nothing.
You probably have enabled one of the other locking options accidentally.

Testing Action Extension with UI Tests

Is it possible to perform UI tests on Action Extension targets? I am unable to create a UI testing target with the Action Extension as the "Target to be Tested." I am trying to load the Action Extension from within Safari (or Photos, although Safari/both is prefered)
If I record my interactions I can get as far as:
app.icons["Safari"].tap()
I can then manually add:
XCUIDevice.sharedDevice().pressButton(.Home)
before the generated code, but it doesn't work as expected (the simulator is left on the home screen).
I have also tried:
UIApplication.sharedApplication().openURL(NSURL(string: "https://google.com")!)
but that also doesn't open Safari.
I'm not even sure if I'll be able to interact in an automated with with the Action Extension if it does get launched, but hopefully it'll be possible.
So, it's possible to switch apps with XCUITest, but it's undocumented. If you check out Facebook's WebDriverAgent, they did a header dump and made a helper for launching from the springboard. You can call:
XCUIApplication* safari = [[XCUIApplication alloc] initWithPrivatePath:nil bundleID:#"com.apple.safari"];
[safari launch];
And then interact with Safari just like you do your app. However, I've run into a similar problem where XCUITest won't actually launch the extension itself. Once open (i.e. you tap physically on the extension button while the test is running), the test runner works perfectly, and you can interact with your extension in the same context as your app. However, having the test runner tap to launch the extension does nothing. I've also got an Apple Dev Forum question going on this topic.
Update:
It turns out if you use the app to press the screen at the location of the button, the extension will load and you can interact with it! Note that the API for tapping a coordinate is very wonky. The x, y are multipliers of the frame of the thing that you created the coordinate from. Relevant sample code:
// app is your XCUIApplication
// In this case we are tapping in the horizontal middle and at the y coordinate 603 (this is for a 6+ screen size)
XCUICoordinate* coordinateOfRowThatLaunchesYourExtension = [app coordinateWithNormalizedOffset:CGVectorMake(0.5, 603.0 / 736.0)];
[coordinateOfRowThatLaunchesYourExtension tap];
This will press the button for your extension in the action sheet, after Apple's extension picker has been invoked. For whatever reason / bug in XCUITest simply pressing your app in the action sheet doesn't work:
[app.sheets.staticTexts[#"MyApp"] tap];

Resources