Getting Started with Unit Testing in Swift

Getting set up to write unit tests in Swift, while not difficult, isn’t exactly intuitive. I’ve written several posts and gathered a few resources on unit testing in Swift, but I haven’t yet published a “getting started” guide until now.

Where does one get started with unit testing in Swift when they’ve never gotten started before? Here are 5 steps to help you successfully begin unit testing in Swift:

1 – Create your project

The obvious first step. If you don’t already have a project going, create a new one to organize the code for your app idea. XCode 6 will automatically generate two “targets” for you. One will be your app’s main module and contains all the code which, when compiled, is meant to be run in the iOS simulator / on an iOS device.

The other will be your test target, which, as the name implies, is where you write your unit test code.

It’s important to note that there are two compilation targets that you’ll be working with as you unit test. Source code that’s part of one compilation target isn’t part of the other by default. This is important to at least know as we move forward in this walkthrough.

2 – Framework considerations: toggle “Defines Module” in your build settings

This step becomes especially critical if you’re using or plan to use a unit testing framework like Quick. It’s not required to use something like Quick, but it can enhance your testing experience if you prefer something other than the out-of-the-box XCTestCase setup.

When you’re working with frameworks, Apple recommends that you make sure the “Defines Module” build setting, found under Packaging, is set to Yes.

If you are relying on, or could be relying on “non-standard” .framework files for your app, make sure you toggle this flag in your XCode build settings:
Build Settings - Defines Module

3 – Import your main project (module) into your test file(s)

In your test target, at the top of each of your .swift files that contain your XCTestCase classes, write an import statement to bring in your main project’s module. In normal scenarios, your app’s module is named the same as your XCode project file.
Import Module for Testing

4 – Access control: Public == Testable

Any classes/structs/enums/methods that you need to use in your tests must have a public access control modifier. Internal (default) and private Types and functions can’t be “seen” by your unit tests, so you need to go the public route if you want to test those things.

Previously I’d written on Swift access control and its implications for unit testing. There, I proposed simply adding your main project’s .swift source files to your test target, but it turns out that this can lead to some really obscure issues. An enlightening Twitter conversation also shed some light on the subject, and pointed to the solution of testing only publicly accessible behavior that your Types expose, rather than trying to test internal implementation. That probably deserves a blog entry of its own, but for now, I’ll leave it to say that I’d recommend not adding your .swift source files to your test target, but rather to adjust the access control modifiers of the things you want to test to public.

5 – Write tests!

With your main project imported into a test file, and your Types and functions declared with appropriate public accessibility, you’re all set to begin writing tests in Swift!

Summary

We’ve gone from 0 to ready-to-test in this getting started guide to unit testing in Swift. From here, you may be interested in pursuing other topics related to unit testing in Swift. Check out my ever-growing unit testing resource list for more information!

  • Pingback: Swift Unit Tests - A Solution for "Use of unresolved identifier"()

  • Pingback: Swift Unit Testing Resources - Andrew Bancroft()

  • Pingback: Getting Started with Unit Testing in Swift | Dinesh Ram Kali.()

  • Pingback: Swift Unit Testing - Verifying Method Calls - Andrew Bancroft()

  • Pingback: Xcode 6: Usable Testing « Under The Bridge()

  • James

    Hi Andrew, thanks for the blog post. I have followed the steps you have outlined but my XCTestCase does not seem to want to recognise the import that I put at the top of the file. I have set Defines modules to YES at the project level, but still no solution. Would you mind taking a quick look?
    I have tried creating a new project and following your steps seemed to work.
    Would you mind having a quick look to see if you can recognise anything fishy going on?
    https://github.com/pangers/gamurs-ios-app

    • Andrew Bancroft

      Hey James!

      Did you get it working? I tried to visit the GitHub link you posted, but I got a 404. Let me know – I’m happy to troubleshoot with you if you still need help.

      If you fixed it already, that’s awesome too – could you share what the trouble was?

      • James

        Hi Andrew, yes I discovered it was a rookie error. My main module had hyphens in the name so putting “import main-Module” was giving an error as the compiler was complaining about me using a minus symbol in the import.

        However, I do have another problem that I am currently struggling with which I have made a detailed post about on stack overflow with a working GitHub. Would love your perspective on this new problem.

        http://stackoverflow.com/questions/28733016/view-controller-tdd

        Thanks for your blogs Andrew!

        • Andrew Bancroft

          Very glad you figured it out. I wouldn’t have guessed having hyphens in the module name would cause problems, but hey – now we know!

          I saw that Brian answered your Stack Overflow question and that it was marked as accepted. Man – I’m wicked slow at responding, apparently! haha

          If you still need help, I’m always happy to explore more solutions. It may just take me a while. :]

          • James

            Yep, with the help of the answers in the thread, I solved the elusive problem of testing view controllers once and for all! I updated my OP in the thread if you would like to take a look. I should really start a blog documenting these things..

          • Andrew Bancroft

            Great!

            And yes – you really –should– start a blog documenting what you’re discovering. Seriously! A great majority of the things I write about are things that took me time to figure out. If it took time, it -must- mean there aren’t enough resources that explain it a way that makes sense to my brain, so I figure, why not write about it? Maybe someone else things like me (terrifying!) and could be helped.

            I say go for it. :]

  • Pingback: Creating Trust-able Unit Tests in Swift - Andrew Bancroft()