Manbolo Blog

Manbolo Team Blog, creators of MeonArchives

Launching UIAutomation Tests in Command Line

Xcode, I don’t want the iPad Simulator!

If you don’t know UIAutomation yet, I encourage you to check this very good presentation (warning: [self doPromotion]!).

While installing a Jenkins to automatically build one of the app I work on, I’ve encountered some issues trying to launch automated tests with the command line. Specifically, with the current version of Xcode (4.6.1), there is no simple way to set the Simulator device type when you’re testing/launching an Universal app. As a good iOS citizen, I’ve filled a bug report waiting for Apple to correct this. In the mean time, fortunately, there is a workaround.

Forcing the Simulator

1. Overriding TARGETED_DEVICE_FAMILY

The first step to this workaround is to force the device family of your app build. There are two solutions to do this:

I prefer the latter solution, because you don’t need to ’split’ your target and you can keep it Universal. The overriding could only be used by your Jenkins server for instance, while doing automated tests.

Let’s take an example. With Xcode 4.6.1, build your app in command line

xcodebuild -project "/Users/jc/Documents/TestExample/TestExample.xcodeproj" \
-scheme TestExample \
-sdk iphonesimulator6.1 \
-configuration Release \
SYMROOT="/Users/jc/Documents/TestExample/build" \
DSTROOT="/Users/jc/Documents/TestExample/build" \
install

Finally, install is the command to build the target and install it into the target’s installation directory in the distribution root.

Doing this, your app is build as an Universal binary. Then, if you want to lauch UIAutomation tests on it, you will use

instruments \
-t  "/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate" \
"/Users/jc/Documents/TestExample/build/Applications/TestExample.app" \
-e UIASCRIPT absolute_path_to_the_test_file  

If you do this, the iPad Retina Simulator will always launch.

So to launch the UIAutomation tests with the iPhone Simulator, we can override TARGETED_DEVICE_FAMILY at build time:

xcodebuild -project "/Users/jc/Documents/TestExample/TestExample.xcodeproj" \
-scheme TestExample \
-sdk iphonesimulator6.1 \
-configuration Release \
SYMROOT="/Users/jc/Documents/TestExample/build" \
DSTROOT="/Users/jc/Documents/TestExample/build" \
TARGETED_DEVICE_FAMILY="1"
install

Where TARGETED_DEVICE_FAMILY is set to "1" for iPhone only build, and "2" for iPad only build. Then you can launch your UIAutomation tests and the right simulator will launch. A side note: you can notice that the app folder input of xcodebuild is not necessarily in the iPhone Simulator Sanbox folder (for instance, under ~/Library/Application Support/iPhone Simulator/6.1/Applications/): don’t worry, at the end of the process, the app will be installed by xcodebuild in the Simulator folder.

2. Really launching the right Simulator

But what if you want to test your app in the iPhone 3.5"" Retina Simulator and then in the iPhone 4" Retina Simulator? Forcing TARGETED_DEVICE_FAMILY will allow you basically to switch between iPhone and iPad but you won’t be able to precisely choose the device you launch.

So the second step of the workaround is to use a script by Jonathan Penn in his UI Screen Shooter project: UI Screen Shooter is a set of scripts to demonstrate how to take screen shots for iOS app for the App Store automatically using UIAutomation. One of the script Jonathan has developed is excatly what we need: choose_sim_language. With choose_sim_language, you can open the Simulator with the device you needed. For instance

choose_sim_device "iPhone (Retina 3.5-inch)"  

will launch the iPhone 3.5" Retina Simulator while

choose_sim_device "iPad"  

will launch the 1024x768 iPad Simulator.

Actual values supported by the choose_sim_device are:

Maybe in a near future we will have "iPhone 4.8-inch" ?

I encourage you to visit the UI Screen Shooter GitHub page and the post on Jonathan’s blog. His clever script is using Apple Script under the hood to select the right menu item:

#!/usr/bin/env osascript

(*
Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Chooses a device type from the iPhone Simulator using menu
selection events.

To use, make sure this file is executable, then run from the terminal:

  bin/choose_sim_device "iPad (Retina)"

Originally, I tried to do this by editing the Preference file for the
simulator, and it worked under Xcode 4.3, but now it ignores those changes
often enough that I chose to use this menu-selection route.

*)

-- START:choose.sim.device
on run argv
  set simType to item 1 of argv

  tell application "iPhone Simulator" to activate
  tell application "System Events"
    tell process "iPhone Simulator"
      tell menu bar 1
        -- Hardware menu bar item
        tell menu bar item 5
          -- Hardware menu
          tell menu 1
            -- Device menu item
            tell menu item 1
              -- Device sub menu
              tell menu 1
                click menu item simType
              end tell
            end tell
          end tell
        end tell
      end tell
    end tell
  end tell
  -- END:choose.sim.device

  -- Need to show the simulator again after changing device,
  -- or else the simulator be hidden when launched by instruments
  -- for some odd reason.
  tell application "System Events"
    set visible of process "iPhone Simulator" to true
  end tell

  -- START:choose.sim.device
end run
-- END:choose.sim.device

Wrap up

To launch UIAutomation tests with the right Simulator, with an Universal app:

  1. Build your app and overrides TARGETED_DEVICE_FAMILY

    xcodebuild -project "/Users/jc/Documents/TestExample/TestExample.xcodeproj" \
    -scheme TestExample \
    -sdk iphonesimulator6.1 \
    -configuration Release \
    SYMROOT="/Users/jc/Documents/TestExample/build" \
    DSTROOT="/Users/jc/Documents/TestExample/build" \
    TARGETED_DEVICE_FAMILY="1"
    install
    
  2. Launch the Simulator you want to test

    choose_sim_device "iPhone (Retina 3.5-inch)"
    
  3. Launch your UIAutomation tests

    instruments \
    -t  "/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate" \
    "/Users/jc/Documents/TestExample/build/Applications/TestExample.app" \
    -e UIASCRIPT absolute_path_to_the_test_file  
    

From jc.

All Posts