How We Ensure Long-Term Quality for iOS Apps (Series 2/3)

Nico Lourenço
LumApps Experts
Published in
5 min readJun 19, 2019
CircleCI + Fastlane = ❤️

Introduction

This article is the second of three in the miniseries from the LumApps iOS team, in which we discuss the quality and maintainability of our mobile application.

This one will focus on our continuous integration process.

If you missed it, have a look at the first article written by Thomas Lombard: How We Ensure Long-Term Quality for iOS Apps (Series 1/3)

Technical stack

Circle CI

Circle CI has been a serious competitor when choosing our continuous integration solution. It had to meet with specific criteria:

  • Easy to maintain over time
  • OS X hardware for iOS builds
  • Compatible with the rest of the projects (android / front web / back end)
  • Cloud-based

Circle CI has been an obvious choice, especially via its GitHub integrations.

Fastlane

As we prefer to spend time on code quality rather than performing redundant tasks, we integrated Fastlane to the project.

Fastlane is an open source tool written in ruby developed in order to simplify iOS apps deployment and automate builds & tests workflows.

Here is the non-exhaustive list of our lanes:

  • take_screenshots: Generate new localized screenshots
  • upload_metadata: Upload the screenshots and metadata to AppStore Connect
  • build_release: Generate the IPA on release configuration
  • upload_binary: Upload the IPA to AppStore Connect
  • build_mock_target: Build target containing data mocks
  • lint: Run linter and generate a report file
  • update_localisables: Update localized strings files
  • tests_and_coverage: Run tests and generate coverage and tests reports
  • ui_tests: Run UI tests

Some of these lanes are technical shortcuts, others are intended to avoid human errors or to be faster in our tasks.

The actions made by Fastlane are the same on Circle and in our local environment but the outputs generated can be different. For exemple, we never send a Slack message when we run on local, but we show a notification in the notification center.

Lokalise

To keep our localisables up to date, we use Lokalise.
It allows us to manage and generate translation files in the correct format for Xcode.

Technical prevention

We’ve created two workflows to avoid any technical regression during the development

Build and test

In this workflow, we want to send a Slack summary of the project to check some of these requirements:

  • Number of warnings (build/lint)
  • Check that all targets compile
  • Check that all the unit tests pass
  • Get coverage rate and trend

It’s triggered by every pull request created and merged on git dev branch.

Slack message when running from Circle

Called lanes

  • fastlane lint
  • fastlane build_mock_target
  • fastlane tests_and_coverage

Few words about tests_and_coverage lane.
This lane uses slather to generate a coverage report. We use slather to ignore some directories that are irrelevant, to be excluded from code coverage (typically view controllers, constants…).

Also, in Circle, SwiftLint is not installed on built-in images, we had to use a custom one to get it working.
To get the report generated by SwiftLint we use Circle workflow.

Finally, to calculate code coverage trend, each report is stored, and can be retrieved through Circle API to be compared afterward.

Nightly tests

This workflow runs the UI tests on each targeted device. It sends a Slack summary of the time used to run the UI tests.

As you can see, UI tests can be longer. It’s the reason we execute these tests only one time per day and during the night.

It checks that we do not have a UI regression and also ensures that our critical path is still bug-free on multiple devices. And could also in the future check different OS versions

This workflow is triggered every evening of the week if there have been modifications in the past 24 hours.

Called lanes

  • fastlane ui_tests

Release automation

For each release, we use two separate workflows to optimize build times. Thus the last workflow, which can take longer, will only be executed once the version has been validated internally.

Internal testing

This workflow ensures that all the requirements of the “Build and test” and “Nightly tests” workflows are still good.

In parallel, it updates the localisable files of the project. If there’s some modified files, the workflow fails because the project is missing the latest translations!

If all succeeds, it generates an AppStore IPA, and asks for a developer approval. If the IPA is satisfactory, then the developer (release manager) validates the IPA which will be submitted to the internal test teams through TestFlight.

This workflow is triggered by every push on the internal_testing branch.

Called lanes

  • update_localisables
  • fastlane build_release
  • fastlane upload_binary

Release workflow

When the build is validated by the test team, it’s time to release! 🎉

So, with the validated version we use Fastlane to generate all the screenshots in every supported language for each targeted device.

After that, it sends a Slack message with a package of screenshots, a button to validate the workflow and a link to Circle CI artifacts that contain an HTML that summarizes all the generated screenshots.

When the workflow is validated, the screenshots (and metadata) are uploaded to AppStore Connect.

This workflow is triggered by every push on master branch.

Called lanes

  • fastlane take_screenshots
  • fastlane upload_metadata

Conclusion

Our CI evolves every day. We try to improve it with each production bug or when we realize the recurrent or forbidding nature of a task.

The build times and the duplicate jobs are valid reasons to reevaluate our processes and git workflow and optimize our CI. Finally, the CI allows to:

  • prevent regressions
  • keep a good code quality
  • avoid human errors
  • save time on recurring tasks
  • save time during releases process

Moreover, all of these CI flows can only work when respecting our git workflow.

Thanks for reading! In the next article of this series, we will chat about UI tests.

Nicolas Lourenço, iOS Engineer at LumApps

--

--