Unit Testing in Swift

  • What is unit testing?
  • What to test?
  • Understanding XCTest and XCTestCase
  • Adding a unit test in Xcode
  • Another unit test example
  • Tips for naming
  • Debugging a test
  • Enabling code coverage
  • Automating with Fastlane and Semaphore

Why should you test?

As a software developer, you want to make sure that the code you’re writing is working the way it’s supposed to. It may sound trivial, but codes break, and regressions happen.

What is unit testing?

As the name suggests, this test is for a particular unit — a chunk of code that can be isolated to be tested separately. For example, you can test the network calls, the logic of caching an image, or the computed variables in the data models. You then have a predefined input and can check for the expected value and outcomes for the particular chunk of code in a test.

What to test?

Now you know that it is essential to write tests for your app to benefit from it in the longer term. But, what to test exactly? A question that everyone wonders about. What to write tests about?

Understanding XCTest and XCTestCase

XCTest is a framework by Apple that helps us create and run unit, performance, and UI tests. For now, we’ll focus on creating unit tests only. The framework provides us with two major classes:

  • XCTestCase which is the primary class for defining test cases, test methods, and performance tests inherited from XCTest.
  • Instance methods to set up the initial state and to perform cleanup for each test method. Similarly, we override setUp() and tearDown() instance methods, respectively.

Another unit test example

For this example, we’ll test TallestTowers, an app that displays the tallest towers from around the world and information about them. You can download the project here.

class TowerStaticTests: XCTestCase {
func testTallestTowersShouldNotBeEmpty() {
XCTAssert(Tower.tallestTowers.count > 0)
}
}
class TowerInstanceTests: XCTestCase {
var subject: Tower!

override func setUp() {
subject = Tower(name: "Empire State Building", city: "New York City", country: "USA", height: 381, yearBuilt: 1931, latitude: 40.748457, longitude: -73.985525)
}

override func tearDown() {
subject = nil
}
}
func testLocationShouldBeCreatedFromLatitudeAndLongitudeProperties() {
XCTAssertEqual(subject.location.latitude, 40.748457, accuracy: 0.00001)
XCTAssertEqual(subject.location.longitude, -73.985525, accuracy: 0.00001)
}
func testCityAndCountryShouldConcatenateCityAndCountry() {
XCTAssertEqual(subject.cityAndCountry, "New York City, USA")
}
func testFormattedHeightIncludesUnits() {
XCTAssertEqual(subject.formattedHeight, "381m")
}

Tips for naming

Whenever you are writing a test, follow these best practices:

  • Be specific. If a test fails among many, the glimpse of the name should be enough to give you an idea of what failed. For example, if testTallestTowersShouldNotBeEmpty() fails, you know because the list will be empty.

Debugging a unit test

You can use the standard tools for debugging offered by Xcode to debug the unit tests as well. After checking for any logical or assumption error, use test failure breakpoints to see if the test is still failing or not outputting the expected result.

Enabling code coverage

Xcode has built-in code coverage to test if your tests have reviewed the entire code. To enable this option, go to TallestTowers and click on ‘Edit Scheme’. Select the test option from the sidebar then options from the segmented control. Check ‘Gather coverage for all targets’.

Automating unit test in CI with Fastlane and Semaphore

To automate the testing process, we’ll use Fastlane which is aimed at simplifying deployment. There are various methods of installing Fastlane, and we’ll use Homebrew here. Open Terminal and run the command:

brew install fastlane
fastlane init
lane :tests do
run_tests(scheme: "TallestTowers")
end
fastlane tests

Conclusion

It’s hard to focus on writing tests when there’s a deadline approaching, but many realize that it is beneficial in the long run. Writing tests improves code quality, reduces bugs and regressions, and speeds up your development process over time.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store