如何测试 UIAlertController 的完成处理程序中调用的方法?

Posted

技术标签:

【中文标题】如何测试 UIAlertController 的完成处理程序中调用的方法?【英文标题】:How can I test the method called in the completion handler of a UIAlertController? 【发布时间】:2019-07-07 13:12:30 【问题描述】:

我有一个附加到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 将允许我测试警报是否可见,然后点击 Yes 我可能会被重定向到注销路线,但是我真的对测试方法本身很感兴趣。

但我不确定如何在代码中进行测试。

【问题讨论】:

【参考方案1】:

我试图在 XCTestCase 中断言单击“是”会在我的视图模型上调用正确的方法......我真的对测试方法本身很感兴趣。

实际上还不清楚您究竟想要测试什么。弄清楚这一点(实际上需要测试什么?)是大部分的战斗。当标题为 Yes 时,您知道 resulttrue,因此无需测试有关实际点击此特定警报的任何内容。也许您要求测试的只是这样:

     result in
        guard result else  return 
        self?.viewModel.revokeSession()
    

换句话说,您想知道resulttrue 时会发生什么与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
)

现在您已将函数分解为可独立测试的东西。

【讨论】:

【参考方案2】:

使用ViewControllerPresentationSpy,你的测试可以说

let alertVerifier = AlertVerifier()

创建验证器。然后调用您的presentAlert 函数。接下来,调用

alertVerifier.executeAction(forButton: "Yes")

执行给定的动作。最后,调用捕获的闭包:

alertVerifier.capturedCompletion?()

并验证预期结果。

【讨论】:

以上是关于如何测试 UIAlertController 的完成处理程序中调用的方法?的主要内容,如果未能解决你的问题,请参考以下文章

显示没有按钮的 UIAlertController 时 UI 测试失败

如何更改 UIAlertController 高度?

求N以内的所有完数 C语言 看清楚题再回答!!! 请经过测试以后再回答!!!

如何获取 UIAlertController 的框架宽度?

如何在 Swift 中旋转 UIAlertController

如何从 SKScene 呈现 UIAlertController