Unit test your iOS app without Fastlane
Introduction
In this post, I’m going to show you how to run unit tests in your iOS app using the Xcode CLI and Bash. This is a great way to run your tests without having to rely on Fastlane or any other third-party tools. It’s also a good way to get familiar with the Xcode CLI and how it works. You’d want to do this when you have a CI provider that doesn’t have Ruby for some reason, can’t install Fastlane, or just because you want to learn how to do it yourself.
Prerequisites
- Xcode installed
- Xcode CLI tools installed (if you’ve got Xcode, you’ve got these)
- xcpretty installed (optional, but recommended for pretty output)
- A working iOS app with unit tests
Setup
You need to know the names of your project and schemes. You can find this out by opening your project in Xcode and looking at the top-left corner of the window. The project name is the name of the file with the .xcodeproj
extension, and the scheme is the name of the scheme you want to run tests for. For this example, we’ll use MyApp.xcodeproj
and MyAppTests
as the scheme name.
#!/bin/bash
set -u # Only treat unset variables as errors
# Configurable variables
SCHEME="YourSchemeName"
DESTINATION="platform=iOS Simulator,name=iPhone 16 Pro,OS=latest"
PROJECT="YourProject.xcodeproj"
Run tests
We’re going to use xcodebuild
to run the tests. This is the command that Xcode uses under the hood to build and run your app. The command looks like this:
#!/bin/bash
set -u # Only treat unset variables as errors
# Configurable variables
SCHEME="YourSchemeName"
DESTINATION="platform=iOS Simulator,name=iPhone 16 Pro,OS=latest"
PROJECT="YourProject.xcodeproj"
# Run tests and capture exit code
set -o pipefail
xcodebuild test \
-scheme "$SCHEME" \
-project "$PROJECT" \
-destination "$DESTINATION" \
clean test | tee xcodebuild.log | xcpretty
EXIT_CODE=${PIPESTATUS[0]}
if [ "$EXIT_CODE" -ne 0 ]; then
echo "❌ Unit tests failed!"
exit "$EXIT_CODE"
else
echo "✅ All unit tests passed!"
fi
Explanation
Ok, let’s break this down a bit, as it can be quite scary to look at, especially if you’re not used to the command line.
set -u
: This tells Bash to treat unset variables as errors. This is a good practice to avoid bugs in your scripts.SCHEME
,DESTINATION
, andPROJECT
: These are the variables that you can configure to match your project. You can change these to match your project name, scheme name, and destination.set -o pipefail
: This tells Bash to return the exit code of the last command in the pipeline that failed. This is useful for capturing the exit code ofxcodebuild
and checking if the tests passed or failed.xcodebuild test
: This is the command that runs the tests. It takes the scheme, project, and destination as arguments.| tee xcodebuild.log
: This pipes the output ofxcodebuild
to a file calledxcodebuild.log
and also prints it to the console. This is useful for debugging and checking the output of the tests.| xcpretty
: This pipes the output ofxcodebuild
toxcpretty
, which formats the output to be more readable. This is optional, but recommended for better output.EXIT_CODE=${PIPESTATUS[0]}
: This captures the exit code of thexcodebuild
command. If the tests fail, this will be a non-zero value.if [ "$EXIT_CODE" -ne 0 ]; then
: This checks if the exit code is not equal to 0. If it is not, it means the tests failed.echo "❌ Unit tests failed!"
: This prints a message to the console if the tests failed.exit "$EXIT_CODE"
: This exits the script with the exit code ofxcodebuild
.else
: This is the else statement that runs if the tests pass.echo "✅ All unit tests passed!"
: This prints a message to the console if the tests passed.fi
: This closes the if statement.
Running the script
To run the script, save it to a file called run_tests.sh
and make it executable:
chmod +x run_tests.sh
Then, run the script:
./run_tests.sh
You should see the output of the tests in the console, and if the tests pass, you’ll see a message saying ”✅ All unit tests passed!”. If the tests fail, you’ll see a message saying ”❌ Unit tests failed!” and the script will exit with a non-zero exit code.
Building on top of this
This script is the bare minimum to run unit tests in your iOS app. You can build on top of this by adding more features, such as:
- Running UI tests
- Running tests on a specific simulator
- Running tests on a specific device
- Running tests on a specific OS version
- Running tests in parallel
- Running tests on multiple simulators
And much more! Bash is incredibly flexible, and xcodebuild
is a powerful tool that can do a lot more than just run tests. You can use it to build your app, archive it, export it, and much more. You can find more information about xcodebuild
in the Xcode documentation. It’s quite old, but it still has a lot of useful information.
For a list of all the available options for xcodebuild
, you can have a look here, and you can always run xcodebuild -help
in the terminal to see a list of all the available options.
Conclusion
In this post, we’ve shown you how to run unit tests in your iOS app using the Xcode CLI and Bash. This is a great way to run your tests without having to rely on Fastlane or any other third-party tools. It’s also a good way to get familiar with the Xcode CLI and how it works. Let me know if you have any questions or if you want to see more examples of how to use the Xcode CLI and Bash to run tests in your iOS app. Happy testing!