我正在尝试单独测试我自己的一个类,它正在调用第三方类的方法:
FIRAuth.auth()?.signInAnonymously() { (user, error) in
//
}
我正在使用基于协议的依赖注入来实现这一目标:
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())
}
}
}
}
}
到目前为止一切顺利! 现在,我希望我的mockFIRAuth返回FIRUser的一个实例。 这是我的问题:我自己无法创建FIRUser的实例。
仅供参考:public typealias FIRAuthResultCallback = (FIRUser?, Error?) -> Swift.Void
如果发现这篇很棒的文章解释了如何在第三方类上创建方法,则返回协议而不是类型。 http://masilotti.com/testing-nsurlsession-input/ 也许我的情况与文章的情况不同,但这是我对此的看法:
我已经定义了FIRUserProtocol:
protocol FIRUserProtocol {
var uid: String { get }
}
extension FIRUser: FIRUserProtocol {}
我更新了FIRAuthProtocol以使用FIRUserProtocol而不是FIRUser调用完成处理程序:
protocol FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)?)
}
我已更新FIRAuth扩展程序以支持修改后的协议。我新定义的方法调用signInAnonymously的默认实现:
extension FIRAuth: FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
signInAnonymously(completion: completion)
}
}
最后,我更新了MockFIRAuth以支持修改后的协议:
class MockFIRAuth: FIRAuthProtocol {
var signInAnonymouslyCalled = false
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
signInAnonymouslyCalled = true
}
}
现在,当我运行测试时,一切都停止了:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff586a2ff8)
请指教!
在我的FIRAuthProtocol方法中重命名完成参数标签后,一切似乎都按预期工作:
protocol FIRAuthProtocol {
func signInAnonymously(completionWithProtocol: ((FIRUserProtocol?, Error?) -> Void)?)
}
extension FIRAuth: FIRAuthProtocol {
func signInAnonymously(completionWithProtocol: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
signInAnonymously(completion: completionWithProtocol)
}
}
这解决了我现在的问题,但我仍然想知道为什么我的第一次尝试不成功。这是否意味着它们的闭包中具有不同参数类型的两个方法无法分开,这导致我的应用程序崩溃?
答案 0 :(得分:3)
我终于找到了解决这个问题的优雅方法。
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)
}
}
这样,就不需要改变函数名称或参数标签。