The migration to Swift might very well start in the testing bundle


Unit tests covering Objective-C code can be written in Swift. By following this approach, we can kill two birds with one stone: add testing coverage while starting to introduce Swift into an Objective-C project.

This is hardly news: Swift and Objective-C can coexist in the same project.

If you are having a hard time finding how and where to start adding Swift to a legacy project, or you are not really sure if Swift is for you, or your management thinks Swift is just a fad, or just “syntactic sugar”1, or not mature enough, it might be the moment to turn to your testing bundle.

Killing two birds with one stone

Every piece of software should be unit tested. If your project is not tested, I strongly recommend adding unit tests to it as soon as possible.

So, if your project does not contain any tests, you can kill two birds with one stone, by starting to add tests, writing them in Swift. And if you project already contains tests, one way of dipping your toes into the Swift world could be using Swift to write your unit tests.

Let’s assume we have an Objective-C only project. To complicate things just a little bit, let’s assume this project does not even contain a testing bundle.

Follow these easy steps

  • Add a testing bundle. This step would not be necessary if you already have a testing bundle.

Screen Shot 2016-02-14 at 2.36.53 PM

  • Select Swift as the testing bundle language. Not necessary if you already have a testing bundle.

Screen Shot 2016-02-14 at 2.37.36 PM

  • Add a bridging header to the production bundle. The easiest way to do that, in my opinion, is by adding a dummy Cocoa class, to be removed later, selecting Swift as the language, and letting Xcode take care of adding the header for you. After Xcode adds the header, the new class can just be removed from the project.

Screen Shot 2016-02-14 at 2.38.06 PM

Screen Shot 2016-02-14 at 2.38.17 PM

  • Import the Objective-C class or classes you want to test in the bridging header.
  • Update the testing bundle’s build settings, pointing the the Objective-C Bridging Header setting to the header that was created in step 3.

Screen Shot 2016-02-14 at 2.38.59 PM

  • Add a Test Case, selecting Swift as language.

Screen Shot 2016-02-14 at 2.39.20 PM

  • Write the Test Case in Swift.
  • Enjoy.

The final result would be that a class like this:

@interface Person : NSObject
@property (nonatomic, strong, readonly) NSString *name;
@property (nonatomic, strong, readonly) NSString *surname;

-(instancetype) initWithName:(NSString *) name surname: (NSString *) surname;

@interface Person()
@property (nonatomic, strong, readwrite) NSString *name;
@property (nonatomic, strong, readwrite) NSString *surname;

@implementation Person
-(instancetype) initWithName:(NSString *) name surname: (NSString *) surname
    if (self = [super init])
        _name = name;
        _surname = surname;
    return self;

Can be tested like this:

import XCTest

class PersonTests: XCTestCase {
    private struct Constants {
        static let name = "🌹"
        static let surname = "🐞"
    var person: Person?

    override func setUp() {
        person = Person(name:, surname: Constants.surname)
    override func tearDown() {
        person = nil

    func testPersonNameIsSetProperly() {

Emoji in the unit test! That’s what I call a win-win situation!

You can check out a sample project available in GitHub.

  1. Yep, a CTO told me, less than a moth ago, that “Swift is just syntax” 😳🙄 ↩︎

Leave a Reply

Your email address will not be published. Required fields are marked *