Demo for CI/CD pipeline for iOS Native app(SwiftUI) using CircleCI.
You can see config file here.
- Use macOS large resource class(8CPU, 16GB RAM) to optimise build speed
- Use Ruby Orb to install Fastlane with cache easily.
- Fastlane is used to
- Code signing with fastlane match
- Upload to Firebase app distribution
- Fastlane is used to
- Use macOS Orb to preboot iOS Simulator for UITests.
- Use Context for storing secrets(this time token for Firebase) for across projects.
- Upload test results & visualize in Test Insights.
If you just want to run Xcode UITests(XCUITests), below fastlane is enough.
desc "Run all UITests"
lane :ui_test_all do
run_tests(
scheme: "CircleCIDemoUITests",
devices: ["iPhone 13 (15.4)"]
)
end
However, since UITests takes time, you want to split these tests and run them in multiple macOS VMs and iOS Simulators.
Here's how to create that pipeline.
First, you have to build iOS application, including test files.
Fastlane's run_test
provides build_for_testing
and enables just for building the app and tests, not runnning tests.
You can specify output path in derived_data_path
desc "Run all UITests"
lane :build_for_ui_test do
run_tests(
scheme: "CircleCIDemoUITests",
devices: ["iPhone 13 (15.4)"],
derived_data_path: "dist",
build_for_testing: true
)
end
Then you can upload this path to workspace.
build_for_ui_test:
macos:
xcode: 13.3.1
resource_class: macos.x86.medium.gen2
steps:
- checkout
- ruby/install-deps
- run: bundle exec fastlane build_for_ui_test
- persist_to_workspace:
root: .
paths:
- dist
Next step, we will split tests and run them in multiple macOS VMs and iOS Simulators
Since we alredy built the app and tests in previous step, we can download them from workspace and use.
You should specify derived_data_path
and test_without_building
in fastlane's run_tests
.
desc "Run specific UITests"
lane :ui_test_without_building do |options|
run_tests(
scheme: "CircleCIDemoUITests",
devices: ["iPhone 13 (15.4)"],
only_testing: options[:tests],
derived_data_path: "dist",
test_without_building: true
)
end
run_tests
also provides only_testing
options, so you can split test files in CircleCI and pass parameters.
ui_test_parallel:
parallelism: 2
macos:
xcode: 13.3.1
resource_class: macos.x86.medium.gen2
steps:
- checkout
- macos/preboot-simulator:
device: iPhone 13
version: "15.4"
- attach_workspace:
at: .
- ruby/install-deps
- run:
name: Split tests and run UITests
command: |
CLASSNAMES=$(circleci tests glob "CircleCIDemoUITests/*.swift" \
| sed 's@/@.@g' \
| sed 's/.swift//' \
| circleci tests split --split-by=timings --timings-type=classname)
FASTLANE_ARGS=$(echo $CLASSNAMES | sed -e 's/\./\//g' -e 's/ /,/g')
bundle exec fastlane ui_test_without_building tests:$FASTLANE_ARGS
- store_test_results:
path: fastlane/test_output/report.junit