UISlider addTarget 和 sendActions 在 UT 中不起作用

Posted

技术标签:

【中文标题】UISlider addTarget 和 sendActions 在 UT 中不起作用【英文标题】:UISlider addTarget and sendActions not working in UTs 【发布时间】:2017-05-19 15:17:38 【问题描述】:

当我在标准 MVC 项目中运行此代码时,一切正常:我可以以编程方式将操作发送到我的 UISlider。

override func viewDidLoad() 
    super.viewDidLoad()        
    slider = UISlider(frame: CGRect(x: 100, y: 100, width: 200, height: 50))
    slider.minimumValue = 1
    slider.maximumValue = 100
    slider.addTarget(self, action: #selector(sliderTouch), for: .touchUpInside)
    slider.sendActions(for: .touchUpInside)


func sliderTouch(sender: UISlider) 
    print("value: \(sender.value)")

现在由于某种原因,当我想在我的 UT 中模拟 Slider 行为时,它不起作用。这是代码:

func testSlider() 
    let slider = UISlider(frame: CGRect(x: 100, y: 100, width: 200, height: 50))
    slider.minimumValue = 1
    slider.maximumValue = 100
    slider.addTarget(self, action: #selector(sliderTouch), for: .touchUpInside)
    slider.sendActions(for: .touchUpInside)


func sliderTouch(sender: UISlider) 
    print("value: \(sender.value)")

sliderTouch() 在 UT 案例中从未被调用,据我了解,sendActions 不是asnyc,应该直接调用操作方法。

那么为什么我会出现这种行为,我该如何解决呢?

编辑:我还需要它用于其他 UIKit 控件,例如 UISwitchUISegmentedControlUIDatePicker 等...

【问题讨论】:

你想抓住机会吗? 以什么方式测试您的组件与 UIKit 提供的动作调度功能?如果你想测试你的触摸处理,你可以直接调用action方法,比如sliderTouch(sender: slider)。 (这无助于澄清这一点,您的 testSlider 测试函数没有实际的测试断言,因此总是通过。) @JeremyW.Sherman 我的用例不是上面的 sn-p。我刚刚写了 sn-p 来说明主要问题是什么。实际上,我在库中有一个自定义 Slider,它以某种方式对动作调度做出反应,我想测试该行为是否正确。我没有在上面的 sn-p 中写断言,所以我尽量不混淆你并保持问题清晰:) 【参考方案1】:

在测试框架目标中包含的类时,我遇到了与您类似的问题。

这是Apple's documentation的摘录:

当发生特定于控件的事件时,控件会立即调用任何关联的操作方法。 Action 方法通过当前的 UIApplication 对象进行调度,该对象会找到一个合适的对象来处理消息,如果需要,跟随响应者链。

在框架中测试类时没有UIApplication 对象,因此无法调度事件。

您可以在测试目标设置中添加主机应用程序。如果您没有宿主应用程序,您可以创建一个空的 ios 应用程序并使用它。

另见this post。

更新:

以下是设置主机应用程序的方法:

如果下拉列表中没有应用程序,只需创建一个新目标并使用 应用程序 > 单视图应用程序模板。

你已经完成了,你的测试现在应该可以工作了。没有额外的步骤。

【讨论】:

这是正确的!我会考虑添加这个主机应用程序。如果有效,我会标记为正确 Vasili Muravev 在他的答案的 cmets 中指出了一种方法,并且似乎被 ReactiveCocoa 采用。它对我有用。你认为你的方法更好吗?让我知道,因为我找不到简单的方法来做到这一点。但无论如何,你的回答正确地给了我一个“为什么它不起作用”的答案。再次感谢您。 当然,与任何主题一样,每种方法都有优点和缺点。话虽如此,我认为我的解决方案应该是首选解决方案,因为它不依赖任何额外的代码。方法调配是一件非常强大的事情,但如果您不完全了解发生了什么,它会带来很多陷阱。此外,对于使用相同代码的其他团队成员来说,如果发现自己处于 UIKit 方法实际上并没有像通常那样做的情况下,这可能会非常令人惊讶,因为您交换了它的实现。 至于“简单的方法”,我将在我的帖子中添加一些屏幕截图,说明您需要做什么。 我更新了我的帖子,提供了有关如何设置 Host 应用程序的更多详细信息。如果您还有其他问题,请告诉我。【参考方案2】:

对于 Swift 3: https://github.com/ReactiveCocoa/ReactiveCocoa/blob/ae6ebb7725b3d5d33db039d456797c220720cb99/ReactiveCocoaTests/UIKit/UIControl%2BEnableSendActionsForControlEvents.swift

对于 Swift 2 https://github.com/RACCommunity/Rex/blob/master/Tests/Helpers/UIControl%2BEnableSendActionsForControlEvents.swift

或者尝试子类化:

class TouchSlider: UISlider 
    var touchUpInsideHandler: ((TouchSlider) -> Void)?

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
        touchUpInsideHandler?(self)
        guard let touch = touches.first,
              let imageWidth = currentThumbImage?.size.width else 
            super.touchesBegan(touches, with: event)
            return
        
        let location = touch.location(in: self)
        let newValue: Float = minimumValue + (maximumValue - minimumValue) * Float((location.x - imageWidth / 2.0) / (bounds.width - imageWidth))
        setValue(newValue, animated: true)
        super.touchesBegan(touches, with: event)
    

使用touchUpInsideHandler 管理外部触摸。

【讨论】:

感谢您的解决方案。我担心的是,我不仅需要模拟UISlider,还需要模拟UIDatePickerUISwitch 和许多其他的。对于一个简单的问题,这将是很多子类化和样板文件,你不觉得吗? @GuyDaher 你应该把你的问题具体化;)So why am I getting this behavior, and how can I solve this? 你是对的,我的错。我认为有一个可以应用于所有 UIKit 控件的解决方案。我将编辑问题,谢谢您指出并再次抱歉 @GuyDaher 嗯,它对我有用:Test Case '-[BaseAppV2UnitTests.testTest testSleder]' started. value: 1.0 Test Case '-[BaseAppV2UnitTests.testTest testSleder]' passed (0.004 seconds). @GuyDaher 看看github.com/RACCommunity/Rex/blob/master/Tests/Helpers/…

以上是关于UISlider addTarget 和 sendActions 在 UT 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

UITapGestureRecognizer 和 addTarget 的区别

协议扩展和 addTarget 因 NSInvalidArgumentException 而崩溃

UIbutton frame 和 addtarget 不同

Swift:UIScrollView 和 UIControl - addTarget | addGestureRecognizer - 没有按预期工作

对 addTarget:action:forControlEvents 的 addTarget 指针行为感到困惑:

在同一个类中调用UIButton AddTarget