Performing iOS Unit & UI Tests

Jason Carter
Mobile DevOps & CI/CD/CT
2 min readMay 4, 2020

Testing is essential when it comes to improving and maintaining product quality and performing routine checks which are difficult for humans to perform regularly.

In this article, I will try to explain how to create unit & UI tests for iOS applications very briefly.

Creating tests for iOS applications

We use the XCTest framework to create unit tests in Xcode. Test methods are stored in XCTestCase subclass.

Unit tests can be created using the Test Navigator in Xcode. Open the Test Navigator and click on the + icon in the lower-left corner.

Select New Unit Test Target. You should see the bundle and the XCTestCase subclass created.

You can now use XCTAssert functions to test your models or other assets.

Performing iOS application tests

There are multiple ways to perform the tests and get test results. I usually use Appcircle CI/CD platform to run the tests before or during the build & sign process. This helps me to focus on other things like development while my tests and builds are being performed.

I used the following Ruby script to tell Appcircle to run my tests and include the test results into my build package:

# Instal dependencies
require 'open3'
require 'pathname'
# Check & validate Enviroment Variables
def env_has_key(key)
return (ENV[key] != nil && ENV[key] !="") ? ENV[key] : abort("Missing #{key}.")
end
$project_path = ENV["AC_PROJECT"] || abort('Missing project path.')
$repository_path = ENV["AC_REPOSITORY_DIR"]
$project_full_path = $repository_path ? (Pathname.new $repository_path).join($project_path) : $project_path
$scheme = env_has_key("AC_SCHEME")
$output_path = env_has_key("AC_OUTPUT_DIR")
$test_result_path = "#{$output_path}/test.xcresult"
# Create a function to run test commands
def run_command(command, skip_abort)
puts "@[command] #{command}"
status = nil
stdout_str = nil
stderr_str = nil
Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
stdout.each_line do |line|
puts line
end
stdout_str = stdout.read
stderr_str = stderr.read
status = wait_thr.value
end
unless status.success?
if skip_abort
puts stderr_str
else
abort_script(stderr_str)
end
end
end
# Command to tell Xcode to run tests with parameters
command_xcodebuild_test = "xcodebuild -project #{$project_full_path} -scheme #{$scheme} -destination 'platform=iOS Simulator,name=iPhone 11,OS=latest' -resultBundlePath #{$test_result_path} test COMPILER_INDEX_STORE_ENABLE=NO"
# Run our function and perform the tests
run_command(command_xcodebuild_test,false)
exit 0

Getting test results

Appcircle packs my unit & UI test results along with the .ipa file generated after the build if I also sign the build artifact using iOS provisioning profiles.

If I don’t sign the build artifact, the test results are included in the xcarchive file. I can alternatively disable the build and sign steps in my workflow and get only test results without building or signing the application.

There are 3rd party tools like 🔗 XCParse or 🔗 XCTestHTMLReport to view test results in a more user-friendly way.

--

--