Swift 将类编写为帮助器服务并从另一个类调用它
我正试图理解如何在Swift中实现这一点 例如,假设我有以下UIViewControllerSwift 将类编写为帮助器服务并从另一个类调用它,swift,Swift,我正试图理解如何在Swift中实现这一点 例如,假设我有以下UIViewController class ViewController: UIViewController { let logoutButton: UIButton = { let button = UIButton() button.setTitle("Logout", for: .normal) button.setTitleColor(UIColor.black, fo
class ViewController: UIViewController {
let logoutButton: UIButton = {
let button = UIButton()
button.setTitle("Logout", for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 24)
button.addTarget(self, action: #selector(onPressLogout), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
navigationItem.title = "Logged in"
view.addSubview(logoutButton)
NSLayoutConstraint.activate([
logoutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
logoutButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
@objc fileprivate func onPressLogout() {
AuthService.logOut()
}
}
还有一个AuthService
final class AuthService {
static func logOut() -> Void {
print("Logout Pressed")
}
}
我想做的是在按下onPressLogout
时,在我的AuthService
上调用logOut
我想了解的是,我应该如何以正确和最好的方式访问注销
比如说,像我现在这样?类上的静态方法
我应该创建一个这样的实例吗
lazy var auth = AuthService()
然后通过auth.logout()
调用logout,而不使用static
关键字
我对创建这些“助手”类的最佳方法感到困惑。 我不知道AuthService的确切用法,但你可以考虑用一种模式来写。 这保证只启动类的一个实例。单例模式示例:
URLSession.shared
,UserDefaults.standard
<> P>这样,您就可以像“代码> AuthService”、“共享”、“登录”()、“代码”>或“代码> AuthService”、“共享”、“ISUSER LogGEDIN < /代码> < P>我不知道AuthService的确切用法,但您可以考虑将其写入模式。 这保证只启动类的一个实例。单例模式示例:
URLSession.shared
,UserDefaults.standard
这样,您就可以通过类似于
AuthService.shared.logout()
或AuthService.shared.isUserLoggedIn
的方式访问它。我可能会使用
这将允许您调用类似于
AuthService.shared.logOut()的方法我可能会使用
这将允许您调用类似于AuthService.shared.logOut()的方法使用单例是一种常见的做法
对于可测试性,我建议将AuthService作为依赖项注入。首先,我要创建一个协议:
protocol AuthServiceProtocol {
func logOut()
}
然后我将使我的服务符合该协议。(注意:这个类可以设置为一个单例,对于我在这里演示依赖注入的目的来说,这并不重要。)
我将向视图控制器添加一个类级变量:
class ViewController: UIViewController {
var authService: AuthServiceProtocol?
//existing code...
}
注销功能需要更改如下:
@objc fileprivate func onPressLogout() {
authService?.logOut()
}
创建视图控制器后,我会将服务传递给它:
let vc = ViewController()
vc.authService = AuthService()
就这样。我可以在这样的操场上进行测试:
//TEST by forcing view to load and sending fake button touch event
let _ = vc.view
vc.logoutButton.sendActions(for: .touchUpInside)
//prints... "Logout Pressed"
现在,我可以编写一个真正的单元测试,通过一个没有依赖关系的模拟服务。这使我能够更可靠地测试视图控制器。使用单例是一种常见做法
对于可测试性,我建议将AuthService作为依赖项注入。首先,我要创建一个协议:
protocol AuthServiceProtocol {
func logOut()
}
然后我将使我的服务符合该协议。(注意:这个类可以设置为一个单例,对于我在这里演示依赖注入的目的来说,这并不重要。)
我将向视图控制器添加一个类级变量:
class ViewController: UIViewController {
var authService: AuthServiceProtocol?
//existing code...
}
注销功能需要更改如下:
@objc fileprivate func onPressLogout() {
authService?.logOut()
}
创建视图控制器后,我会将服务传递给它:
let vc = ViewController()
vc.authService = AuthService()
就这样。我可以在这样的操场上进行测试:
//TEST by forcing view to load and sending fake button touch event
let _ = vc.view
vc.logoutButton.sendActions(for: .touchUpInside)
//prints... "Logout Pressed"
现在,我可以编写一个真正的单元测试,通过一个没有依赖关系的模拟服务。这使我能够更可靠地测试视图控制器。我认为您使用该协议有点过分。从外部注入AuthService
是一个好主意,但是为什么要使用协议呢?对于单元测试来说,使用模拟服务而不是真正的服务是很有价值的。真正的服务可能依赖于难以控制的外部数据或网络。我知道,但它也会让你的整个应用程序充满不必要的协议,这些协议需要维护,并且只由一个类实现。不要对UI进行单元测试。为UI创建集成测试,也就是说,编写一个测试,该测试将实际单击正在运行的应用程序实例中的按钮。您不能对UI进行单元测试,因为UI只是UIKit、数据模型和服务之间的连接器,所以您的测试最终会复制UI代码。去那里,这不是个好主意。代码覆盖率很高,但实际上没有发现bug。好的,我们可以不同意。我已经成功地对视图控制器进行了单元测试。UI与其他代码没有任何不同。您编写的代码仍然可能存在bug。也许你的UI代码是没有bug的,但是我已经用这种技术在我的代码中发现了bug。我认为你在这个协议上走得太远了。从外部注入AuthService
是一个好主意,但是为什么要使用协议呢?对于单元测试来说,使用模拟服务而不是真正的服务是很有价值的。真正的服务可能依赖于难以控制的外部数据或网络。我知道,但它也会让你的整个应用程序充满不必要的协议,这些协议需要维护,并且只由一个类实现。不要对UI进行单元测试。为UI创建集成测试,也就是说,编写一个测试,该测试将实际单击正在运行的应用程序实例中的按钮。您不能对UI进行单元测试,因为UI只是UIKit、数据模型和服务之间的连接器,所以您的测试最终会复制UI代码。去那里,这不是个好主意。代码覆盖率很高,但实际上没有发现bug。好的,我们可以不同意。我已经成功地对视图控制器进行了单元测试。UI与其他代码没有任何不同。您编写的代码仍然可能存在bug。也许你的UI代码没有bug,但我用这种技术发现了代码中的bug。你问错了问题。您的代码有一个致命的缺陷:您的onPressLogout
将永远不会被调用!所以你永远不能打电话给你的助手或其他任何事情。你的按钮坏了。你问错问题了。您的代码有一个致命的缺陷:您的onPressLogout
将永远不会被调用!所以你永远不能打电话给你的助手或其他任何事情