Testing in Swift for Dummies: Part 1 — Laying the Foundations

Edoardo Troianiello
5 min readJul 28, 2023

--

Hey there, Swift enthusiast! 🚀 Have you ever found yourself amidst a sea of code, fingers crossed, hoping nothing breaks with the next update? Enter the world of testing — a coder’s best friend and an app’s safety net. This guide will demystify the basics of testing in Swift, setting you on the path to coding confidence.

Setting the Stage

Every great act needs a stage, and in the realm of Swift testing, our stage is Xcode:

  • Xcode’s Testing Framework: It’s more than just an IDE; Xcode provides a robust suite of testing tools. You don’t need third-party solutions; everything you require is built-in.
  • Testing Target: Just as every act needs its spotlight, every codebase needs its testing target. The testing target is a separate space where your tests will reside.
  • Test Case Basics: Think of a test case as a mini-story where your code is the protagonist. This story lays out a scenario, lets the protagonist act, and then checks if the ending is as expected.

Adding a Testing Target:

  1. Open your Xcode project.
  2. Choose File > New > Target.
  3. Select iOS Unit Testing Bundle or a relevant testing bundle for your platform.
  4. Name the target appropriately and click Finish.
  5. Now, in the Project Navigator (the left sidebar), you’ll see a new group with the name you chose for your test target. This is where all your test cases will reside.
Adding a target from XCode templates

Crafting Your First Unit Test

Diving into testing may seem intimidating, but fear not! Let’s walk through it step-by-step:

  • Understanding a Unit Test: Picture unit tests as microscopes. They allow us to examine tiny bits of our code in isolation. With a unit test, we can ask our code, “If I give you X, will you give me Y?” If it does, it passes. If it doesn’t, it fails, telling us where something went wrong. This allows us to catch and fix bugs before they become problems.

For instance, let’s imagine we’re developing a calculator app. We have a function that adds two numbers.

How can we be sure this function works as expected?

Writing a Unit Test: With our add function, we know that giving it 2 and 3 should return 5.

Here’s what’s happening in the test:

  • We call the function add with the arguments 2 and 3.
  • We store the return value in sum.
  • We then use an XCTAssertEqual function to check if sum is equal to 5.
  • If sum is not 5, the test will fail and print the error message "2 + 3 should equal 5".

The Magic of XCTAssert: The XCTAssert functions in Swift are like your code’s personal “truth detectors”. They determine if your code behaves as expected. A failed assert tells you something's off; a passed one gives you a green light. Here are a few examples:

  • XCTAssertEqual(a, b): Checks that a is equal to b.
  • XCTAssertNotEqual(a, b): Checks that a is not equal to b.
  • XCTAssertTrue(a): Checks that a is true.
  • XCTAssertFalse(a): Checks that a is false.

These functions provide an arsenal of tools to test a wide range of situations. With these, you can test anything from mathematical calculations to the presence of certain elements in an array.

Unit testing is all about predicting what your code will do and checking if it meets those expectations. It’s an invaluable skill that’ll make your life as a developer much easier. Stay tuned as we delve deeper into the world of testing in Swift in the following sections!

Writing the Tests

Creating a Test Case File: Every test you write in Xcode belongs to a test case. Think of this as a dedicated notebook for a subject. In our context, the subject is a particular class or module you want to test.

  1. Open your Xcode project.
  2. In the Project Navigator on the left, find the group (folder) you’ve designated for tests (typically named after your test target).
  3. Right-click on the group > New File > select Unit Test Case Class.
  4. Give your test case file a descriptive name. If you’re testing a class named Calculator, you might name your test case file CalculatorTests.
  5. Click Next and then Create.

Understanding the Test Case Structure: When you create a new test case file, Xcode provides you with a boilerplate. It includes setup and teardown methods and an example test method. The setup method is where you can initialize variables or resources needed for your tests. The teardown method is where you release them. These methods run before and after each test, ensuring a fresh environment for every test scenario.

Writing the Actual Test: Now, let’s craft our test method. This is where we’ll verify our application’s functionality. Test methods in Xcode should always start with the word “test”. This tells Xcode that it’s an actual test to be executed. The rest of the name should describe what the test does.

Annotating Your Tests: Adding comments or descriptions to your tests can make them even clearer. While your tests should be self-explanatory, annotations can offer more context, especially for more complex testing scenarios.

Organizing Multiple Tests: As your project grows, you’ll likely have multiple test functions in a single test case file. Organize them logically. For our calculator example, you might have testSubtraction, testMultiplication, and so forth. Grouping related tests together makes your test suite easier to navigate and maintain.

Practical Example

Let’s try to test this Calculator Class:

An example of the tests we can perform on the class functions :

Mocking and Stubbing: The Illusionists of Testing

In testing, we often need to ‘pretend’ a bit:

  • The Need to Mock or Stub: Imagine testing a function that fetches data from a remote server. You wouldn’t want your test to depend on server uptime, would you? Mocking and stubbing let you mimic real-world behaviors without the unpredictability.
  • Dependency Injection Explained: Picture a coffee machine. You can either let it fetch water from a source (hard to test) or you can feed it a specific amount (easy to test). That’s what dependency injection is — providing our functions or objects with what they need, making the process controllable and testable.
  • The Power of Stubbing Libraries: While native tools are handy, sometimes third-party libraries like OHHTTPStubs simplify complex tasks, like stubbing network calls. They allow you to set predefined responses for certain requests, ensuring consistency in tests.

Wrapping Up Part 1

Whew! That was a lot, wasn’t it? 🎉 You’re now armed with the basics of testing in Swift. As you venture forth, remember: each test is a building block towards a more robust app. It’s a safety net, ensuring fewer crashes and happier users.

Happy testing!

--

--

Edoardo Troianiello

Computer Engineer | iOS Developer | Alumni @Apple Developer Academy in Naples