Unit-Tests in Swift

Being quick and nimble

Jan Olbrich
Aug 22, 2017 · 2 min read

After our excursion to Unit-Tests with Objective-C let's return to our project. Swift is similar and at the same time entirely different. Suddenly we are statically typed, have access modifiers and can't work with the runtime. Introducing Quick and Nimble. They are RSpec in Swift.

Quick

As with Kiwi I prefer syntactic sugar, which is provided by Quick. Once again we have the same state types as usual in Behavior Driven Development (BDD) based framework:

  • Describe

Nimble

Instead of having just one framework, the Quick project provides Nimble for assertions. As before this is mainly about readability and syntactic sugar rather than providing features not being in XCTest.

expect(sut).notTo(beNil())

Hacking Private

While we had categories in Objective-C we can't use the same trick for Swift. Instead there is the @testable keyword. Importing a module with this, will provide all the module internal variable and functions. Regrettably private and fileprivate methods are not included. But wanting to test these, shows you are coupling your tests too tightly to your software.

@testable import SomeClass

Mock Objects

There is no proficient mock framework for Swift. This results in us having to create our own techniques to mock objects. My preferred way coincides with the way I develop. In my opinion you should not pass specific classes. Instead use protocols. Having for every passable class a protocol will help us replacing them with mocks.

In our system under test, we use protocols as types for our dependencies:

var testObject: TestProtocol = TestClass()

With the protocol in place, we can create our mock class:

class TestMock: TestProtocol {
//implemented method stubs
}

Having this accessible in tests, we can initiate the object and replace the dependency with our mock:

it("") {
let mock = NetworkMock()
sut.network = mock
....
}

Sooo, what will we do using Classes we don't own? Every day we have them: NSUserDefaults, AVAudioPlayer, UNUserNotificationCenter and more.

It's rather simple. Using the same technique, there is also the option to replace class we do not own. Just create a protocol with the methods you will be using and with an extension you can make this class conform to your protocol e.g. UserDefaults:

Conclusion

Knowing these basic techniques we will be able to work test-driven in our app. It's not as easy as it was with Objective-C but maybe having these obstacles will improve our ability to write the right tests.

Next: Testing Apples MVC

Previous: Unit-Tests in Objective-C

Mobile Quality

Everything you need to improve the quality of your mobile app

)

Jan Olbrich

Written by

iOS developer focused on quality and continuous delivery

Mobile Quality

Everything you need to improve the quality of your mobile app

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade