Hire Us
iOS Integration Tests With Appium

iOS Integration Tests With Appium

I came from the RoR web development and – as we all know – Rails community loves tests. Personally, I am a fan of acceptance testing and using mostly capybara for it. So, when I shifted to the iOS development, it was essential for me to find some decent acceptance testing tools like Apple’s UI Automation, Calabash and Appium. The last one appeared to be a test automation framework of iOS, Android and hybrid apps that supports Ruby among other languages. I’ve chosen it to be the first one to explore and started writing tests for my current real project. Let’s see now whether Appium stack is a good choice for the our purposes.

To start with, we need 3 things to run integration tests with Appium:

  • Appium server
  • application package
  • test script

Appium Installation

There are two ways to install Appium: download packaged app or install it via npm. I tried to install it via npm, but it didn’t work, so I opted for a bundled app and successfully ran couple examples. Then, however, I decided to fix my Appium npm install and managed to run it from console by completely reinstalling node and manually cleaning /usr/local/share/npm.

$: sudo npm install -g appium
$: appium

Make app build

Below is a simple script to create a build and place it inside the desired folder to easily access it from test whenever required.

xcodebuild -sdk iphonesimulator6.0 \
  -workspace /Users/mishyn/workspace/rw/project-ios/Project.xcworkspace \
  -scheme Project \
  ONLY_ACTIVE_ARCH=NO \
  TARGETED_DEVICE_FAMILY=1 \
  DEPLOYMENT_LOCATION=YES \
  DSTROOT=`pwd`/app

Don’t forget to make scheme Project shared, otherwise you might get the following error:

ld: library not found for -lPods
clang: error: linker command failed with exit pre 1 (use -v to see invocation)

Write spec

Here is the template, so we now need to fill in the flows.

def absolute_app_path
  file = File.join(File.dirname(__FILE__), 'app/Applications/Project.app')
  raise "App doesn't exist #{file}" unless File.exist? file
  file
end

capabilities = {
  'browserName' => 'iOS',
  'platform' => 'Mac',
  'version' => '6.0',
  'app' => absolute_app_path
}

server_url = "http://127.0.0.1:4723/wd/hub"

describe "Computation" do
  before :all do
    @driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => server_url)
   end

  after :all do
    @driver.quit
  end

  it "should open search" do
    @driver.find_elements(:tag_name, '*')
  end
end

Finding elements

Selenium operates with views similar to HTML DOM elements’ and it looks like this:

@driver.find_elements(:tag_name, 'collectionCell')

Guess how to find tableCells? Right:

@driver.find_elements(:tag_name, 'tableCell')

To get all elements use

@driver.find_elements(:tag_name, '*').map(&:tag_name)
# =>

In the end, you will need only visible buttons

@driver.find_elements(:tag_name, 'button').select(&:displayed?).map(&:text)

Looks good so far.

To click on a button named “Done”, you can use:

@driver.find_element(:name, 'Done').click

In the real world, however, there are too many buttons with custom images; so, in this case we have to use accessibilityIdentifier.
Set accessibilityIdentifier to ‘Done’ in the code, and in the tests use

find_element(:name, 'Done')

More docs:

Github Wiki
Finding-and-interacting-with-elements

Examples:

examples/ruby/u_i_catalog.rb

Tips and tricks

Debugger

I use byebug for Ruby 2.0 as it allows me easily play with UI elements.

Networking

Finally, almost every real application communicates to remote server and this is also something that we want to test. So, as we test our app from outside, we mock webserver outside as well. To run server with mocked api, I use sinatra rb.

Final flow.

#run appium
#run sinatra mock
#build app
#run spec

I’ve personally found Appium very useful, especially taking into account that it doesn’t require any code inside the application.
On the other hand, it requires a lot of prep work to run tests. So, In order to make start with Appium easier, I’ve created a simple gem :
appium-rspec-bootstrap

Hope you’ll find it handy too. Any comments and suggestions are very welcome.