如何测试在 UIAlertController 的完成处理程序中调用的方法?
How can I test the method called in the completion handler of a UIAlertController?
我有一个附加到 UIViewController
的协议,我希望允许显示 UIAlertController
。
import UIKit
struct AlertableAction {
var title: String
var style: UIAlertAction.Style
var result: Bool
}
protocol Alertable {
func presentAlert(title: String?, message: String?, actions: [AlertableAction], completion: ((Bool) -> Void)?)
}
extension Alertable where Self: UIViewController {
func presentAlert(title: String?, message: String?, actions: [AlertableAction], completion: ((Bool) -> Void)?) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
actions.forEach { action in
alertController.addAction(UIAlertAction(title: action.title, style: action.style, handler: { _ in completion?(action.result) }))
}
present(alertController, animated: true, completion: nil)
}
}
然后我只要在我的 UIViewController
中调用这个方法,只要我想显示一个警报
self?.presentAlert(
title: nil, message: "Are you sure you want to logout?",
actions: [
AlertableAction(title: "No", style: .cancel, result: false),
AlertableAction(title: "Yes", style: .destructive, result: true)],
completion: { result in
guard result else { return }
self?.viewModel.revokeSession()
}
)
我试图在 XCTestCase
中断言单击 Yes 会在我的视图模型上调用正确的方法。
我知道 UITest
将允许我测试警报是否可见,然后可能会在点击 是 我被重定向到注销路线,但我真的有兴趣测试方法本身。
不过我不确定如何在代码中对此进行测试。
I am trying to assert within a XCTestCase that clicking Yes calls the correct method on my view model ... I am really interested in testing the method itself.
目前还不清楚你到底想测试什么。弄清楚(究竟什么需要测试?)是大部分的战斗。您知道当标题为 Yes 时 result
是 true
,因此无需测试任何有关此特定警报的实际点击的信息。也许你要测试的只是这个:
{ result in
guard result else { return }
self?.viewModel.revokeSession()
}
换句话说,您想知道当 result
是 true
时会发生什么,而当它是 false
时会发生什么。如果是这种情况,只需将匿名函数替换为真实函数(方法)即可:
func revokeIfTrue(_ result:Bool) {
guard result else { return }
self?.viewModel.revokeSession()
}
并重写您的 presentAlert
以将该方法作为其完成:
self?.presentAlert(
title: nil, message: "Are you sure you want to logout?",
actions: [
AlertableAction(title: "No", style: .cancel, result: false),
AlertableAction(title: "Yes", style: .destructive, result: true)],
completion: revokeIfTrue
)
现在您已将函数分解为可独立测试的部分。
使用ViewControllerPresentationSpy,你的测试可以说
let alertVerifier = AlertVerifier()
创建验证器。然后调用您的 presentAlert
函数。接下来,调用
alertVerifier.executeAction(forButton: "Yes")
执行给定的操作。最后,调用捕获的闭包:
alertVerifier.capturedCompletion?()
并验证预期结果。
我有一个附加到 UIViewController
的协议,我希望允许显示 UIAlertController
。
import UIKit
struct AlertableAction {
var title: String
var style: UIAlertAction.Style
var result: Bool
}
protocol Alertable {
func presentAlert(title: String?, message: String?, actions: [AlertableAction], completion: ((Bool) -> Void)?)
}
extension Alertable where Self: UIViewController {
func presentAlert(title: String?, message: String?, actions: [AlertableAction], completion: ((Bool) -> Void)?) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
actions.forEach { action in
alertController.addAction(UIAlertAction(title: action.title, style: action.style, handler: { _ in completion?(action.result) }))
}
present(alertController, animated: true, completion: nil)
}
}
然后我只要在我的 UIViewController
中调用这个方法,只要我想显示一个警报
self?.presentAlert(
title: nil, message: "Are you sure you want to logout?",
actions: [
AlertableAction(title: "No", style: .cancel, result: false),
AlertableAction(title: "Yes", style: .destructive, result: true)],
completion: { result in
guard result else { return }
self?.viewModel.revokeSession()
}
)
我试图在 XCTestCase
中断言单击 Yes 会在我的视图模型上调用正确的方法。
我知道 UITest
将允许我测试警报是否可见,然后可能会在点击 是 我被重定向到注销路线,但我真的有兴趣测试方法本身。
不过我不确定如何在代码中对此进行测试。
I am trying to assert within a XCTestCase that clicking Yes calls the correct method on my view model ... I am really interested in testing the method itself.
目前还不清楚你到底想测试什么。弄清楚(究竟什么需要测试?)是大部分的战斗。您知道当标题为 Yes 时 result
是 true
,因此无需测试任何有关此特定警报的实际点击的信息。也许你要测试的只是这个:
{ result in
guard result else { return }
self?.viewModel.revokeSession()
}
换句话说,您想知道当 result
是 true
时会发生什么,而当它是 false
时会发生什么。如果是这种情况,只需将匿名函数替换为真实函数(方法)即可:
func revokeIfTrue(_ result:Bool) {
guard result else { return }
self?.viewModel.revokeSession()
}
并重写您的 presentAlert
以将该方法作为其完成:
self?.presentAlert(
title: nil, message: "Are you sure you want to logout?",
actions: [
AlertableAction(title: "No", style: .cancel, result: false),
AlertableAction(title: "Yes", style: .destructive, result: true)],
completion: revokeIfTrue
)
现在您已将函数分解为可独立测试的部分。
使用ViewControllerPresentationSpy,你的测试可以说
let alertVerifier = AlertVerifier()
创建验证器。然后调用您的 presentAlert
函数。接下来,调用
alertVerifier.executeAction(forButton: "Yes")
执行给定的操作。最后,调用捕获的闭包:
alertVerifier.capturedCompletion?()
并验证预期结果。