Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock UIApplication in Swift?

I'm currently using Quick + Nimble for my unit testing in Swift. I'm building an Inviter class that sends app invites via different methods.

I need to mock out UIApplication to verify that my code calls openURL.

My code so far:

import Quick
import Nimble
import OCMock

extension Inviter {
    convenience init(usingMockApplication mockApplication: UIApplication) {
        self.init()
        application = mockApplication
    }
}

class MockUIApplication : UIApplication {
    var application = UIApplication.sharedApplication()

    var openedURL: String?

    override func openURL(url: NSURL) -> Bool {
        openedURL = url.absoluteString
        return true
    }
}

class InviterSpec: QuickSpec {
    override func spec() {

        describe("Inviter") {
            var mockApplication = MockUIApplication()
            var inviter = Inviter(usingMockApplication: mockApplication)

            beforeEach() {
                inviter = Inviter(usingMockApplication: mockApplication)
            }

            context("for WhatsApp invites") {
                beforeEach() {
                    inviter.inviteViaWhatsAppWithMessage("Invite Message.")
                }

                it("should tell the application to open WhatsApp") {
                    expect(mockApplication.openedURL).toNot(beNil())
                }

                it("should send WhatsApp the right message") {
                    let message = mockApplication.openedURL?.lastPathComponent
                    expect(message).to(equal("Invite%Message."))
                }
            }
        }
    }
}

In this approach, my app errors at runtime stating there can understandably be only one UIApplication. Previously, one could make MockUIApplication inherit from NSObject, and pass that in. Unfortunately Swift's strict type checking seems to prevent that too.

Would love any ideas.

like image 202
Christopher Kevin Howell Avatar asked May 14 '15 17:05

Christopher Kevin Howell


1 Answers

You are close. Use a protocol for the functions you need.

protocol UIApplicationProtocol {
    func openURL(url: NSURL) -> Bool
}

extension UIApplication: UIApplicationProtocol {}

Then you just need to use the protocol instead of the class

extension Inviter {
    convenience init(usingMockApplication mockApplication: UIApplicationProtocol) {
        self.init()
        application = mockApplication
    }
}

You will need to modify the Inviter class to use UIApplicationProtocol as well.

like image 176
respectTheCode Avatar answered Nov 02 '22 01:11

respectTheCode