在Swift中模拟第三方课程(Firebase) [英] Mock third party classes (Firebase) in Swift

查看:103
本文介绍了在Swift中模拟第三方课程(Firebase)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对自己的类进行单元测试,该类正在调用第三方类上的方法:

I'm trying to unit test a class of my own which is calling a method on a third party class:

FIRAuth.auth()?.signInAnonymously() { (user, error) in
    //
}

我正在使用基于协议的依赖注入来实现这一目标:

I'm using protocol based dependency injection to achieve this:

protocol FIRAuthProtocol {
    func signInAnonymously(completion: FIRAuthResultCallback?)
}
extension FIRAuth: FIRAuthProtocol {}

class MyClass {
    private var firAuth: FIRAuthProtocol

    init(firAuth: FIRAuthProtocol) {
        self.firAuth = firAuth
    }

    func signIn() {
        firAuth.signInAnonymously() { (user, error) in
            //
        }
    }
}

class MockFIRAuth: FIRAuthProtocol {
    var signInAnonymouslyCalled = false

    func signInAnonymously(completion: FIRAuthResultCallback? = nil) {
        signInAnonymouslyCalled = true
    }

}

class MyClassSpec: QuickSpec {
    override func spec() {
        describe("MyClass") {
            describe(".signIn()") {
                it("should call signInAnonymously() on firAuth") {
                    let mockFIRAuth = MockFIRAuth()
                    let myClass = MyClass(firAuth: mockFIRAuth)
                    expect(mockFIRAuth.signInAnonymouslyCalled).to(beFalse())
                    myClass.signIn()
                    expect(mockFIRAuth.signInAnonymouslyCalled).to(beTrue())
                }
            }
        }
    }
}

到目前为止一切顺利! 现在,我希望我的嘲笑FIRAuth返回FIRUser的实例. 这是我的问题:我自己无法创建FIRUser的实例.

So far so good! Now, I'd like my mockFIRAuth to return an instance of FIRUser. Here's my issue: I can't create an instance of FIRUser myself.

仅供参考:public typealias FIRAuthResultCallback = (FIRUser?, Error?) -> Swift.Void

如果找到这篇很棒的文章,它解释了如何使第三方类上的方法返回协议而不是类型. http://masilotti.com/testing-nsurlsession-input/ 也许我的情况不同于本文的情况,但这是我对此的看法:

If found this great article which explains how to make a method on a third party class return a protocol instead of a type. http://masilotti.com/testing-nsurlsession-input/ Maybe my situation is different than the article's, but here's my shot at this:

我已经定义了FIRUserProtocol:

I've defined a FIRUserProtocol:

protocol FIRUserProtocol {
    var uid: String { get }
}
extension FIRUser: FIRUserProtocol {}

我已经更新了FIRAuthProtocol,以使用FIRUserProtocol而不是FIRUser调用完成处理程序:

I've updated my FIRAuthProtocol to call the completion handler with FIRUserProtocol instead of FIRUser:

protocol FIRAuthProtocol {
    func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)?)
}

我已经更新了我的FIRAuth扩展以支持修改后的协议.我新定义的方法调用signInAnonymously的默认实现:

I've updated my FIRAuth extension to support the modified protocol. My newly defined method calls the default implementation of signInAnonymously:

extension FIRAuth: FIRAuthProtocol {
    func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
        signInAnonymously(completion: completion)
    }
}

最后,我更新了MockFIRAuth以支持修改后的协议:

Finally, I've updated MockFIRAuth to support the modified protocol:

class MockFIRAuth: FIRAuthProtocol {
    var signInAnonymouslyCalled = false
    func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
        signInAnonymouslyCalled = true
    }  
}

现在,当我运行测试时,一切都崩溃了:

Now, when I run my test everything comes to a crashing halt:

Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff586a2ff8)

请指教!

在我的FIRAuthProtocol方法中重命名完成参数标签后,一切似乎都按预期工作:

After renaming the completion argument label in my FIRAuthProtocol's method everything seems to work as expected:

protocol FIRAuthProtocol {
    func signInAnonymously(completionWithProtocol: ((FIRUserProtocol?, Error?) -> Void)?)
}

extension FIRAuth: FIRAuthProtocol {
    func signInAnonymously(completionWithProtocol: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
        signInAnonymously(completion: completionWithProtocol)
    }
}

这现在解决了我的问题,但是我仍然想知道为什么我的第一次尝试失败了.这是否意味着无法将两个在其闭包中具有不同参数类型的方法区分开来,这导致我的应用程序崩溃了?

This solves my issue for now, but I'd still like to know why my first attempt was unsuccessful. Does this mean that the two methods with different parameter types in their closures can't be told apart, which was causing my app to crash?

推荐答案

我终于找到了一种解决此问题的优雅方法.

I've finally found an elegant way to solve this.

protocol FIRAuthProtocol {
    func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)?)
}

extension FIRAuth: FIRAuthProtocol {
    func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
        let completion = completion as FIRAuthResultCallback?
        signInAnonymously(completion: completion)
    }
}

这样,无需更改函数名称或参数标签.

This way, there's no need to alter function names or argument labels.

这篇关于在Swift中模拟第三方课程(Firebase)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆