Using OCMock with Swift
This page decribes my current understanding of using OCMock with Swift. It is updated as Swift evolves.
Last updated for Xcode 7.
General FAQ
Will there be a mock framework for Swift written in Swift?
Maybe. As of now it doesn't look too likely, though, because mock frameworks depend heavily on access to the language runtime, and Swift only offers extremely limited access.
Do I even need a mock framework for Swift?
Yes and no. Swift has many useful language features that allow for more compact code, which should make creating mocks, stubs, and spies in Swift much less tedious than in Objective-C. A blog post by Eli Perkins and another blog post by Jesse Squires describe approaches to testing without a mock framework. Interestingly, the thinking of the people who pioneered mock frameworks and dependency injection over 10 years ago (see "Don't mock third-party libraries" in this post by Steve Freeman) already outlined similar ideas; they were by no means pushing to use mocks for everything.
That said, mock frameworks have proven convenient in many languages. It's not that they are essential, but they do add convenience. Stubbing a factory method to return a mock is quick and easy. Creating a protocol and a wrapper, and using dependency injection is probably more sustainable, but it is also more work and looks more complex. As ever, having options and making the right choice seems key.
Can I use OCMock using the language bridge functionality?
Yes, but with limitations. If you are brave. It's unlikely that OCMock will ever fully support Swift.
Using Swift with OCMock
The code in this section is taken from the SwiftExamples project in the OCMock repository.
Creating a mock for a Swift class
As long as the Swift class inherits from NSObject
it is possible to create a mock for it. Instance methods can be stubbed.
The test is obviously written in Objective-C. It might be possible to write a Swift wrapper around the core OCMock functionality so that tests can be written in Swift.
Using the mock with another Swift object
It is possible to use the mock with a Swift object. Starting with Swift 2 it seems that the Swift object must inherit from NSObject
.
However, note the declaration of the connection
variable in the controller class. Unfortunately, it is necessary to use a protocol. Changing the type from Connection
to ServerConnection
will make the test crash.
Creating a partial mock for a Swift object
Partial mocks can be created for Swift objects that inherit from NSObject
.
The sublassing mechanism used by OCMock seems to work, too. This allows OCMock to stub and verify methods on the real object. Note how we create the partial mock on the controller's existing connection, a Swift object. The controller keeps using a reference to the Swift object it has created, and OCMock can still verify that the fetchData
method has been called.
Known limitations
- Tests have to be written in Objective-C
- Objects that should be mocked must inherit from
NSObject
- References to objects that are replaced with a mock must use protocols
- No stubbing/expecting/verifying of class methods