我正在编写一些单元测试,并且由于这个特定应用程序的性质,重要的是我要尽可能位于
UI
链的较高位置。 因此,我想做的是以编程方式触发按钮按下,就好像用户按下了 GUI
中的按钮一样。
(是的,是的 - 我可以只调用
IBAction
选择器,但是,这个特定应用程序的性质再次使得我伪造实际的按钮按下很重要,以便从按钮调用IBAction
,本身。)
执行此操作的首选方法是什么?
事实证明
[buttonObj sendActionsForControlEvents:UIControlEventTouchUpInside];
在这种情况下,我得到了我真正需要的东西。
编辑: 不要忘记在主线程中执行此操作,以获得类似于用户按下的结果。
对于 Swift 3:
buttonObj.sendActions(for: .touchUpInside)
对 Swift 答案的更新
buttonObj.sendActionsForControlEvents(.TouchUpInside)
编辑:针对 Swift 3 进行了更新
buttonObj.sendActions(for: .touchUpInside)
如果你想做这种测试,你会喜欢 iOS 4 中的 UI 自动化支持。你可以相当容易地编写 JavaScript 来模拟按钮按下等,尽管文档(尤其是入门部分)是一个有点稀疏。
斯威夫特3:
self.btn.sendActions(for: .touchUpInside)
在这种情况下,
UIButton
源自UIControl
。这适用于从 UIControl
派生的对象。
我想在特定用例上重复使用“
UIBarButtonItem
”操作。这里,UIBarButtonItem
不提供方法sendActionsForControlEvents:
但幸运的是,
UIBarButtonItem
具有目标和行动的属性。
if(notHappy){
SEL exit = self.navigationItem.rightBarButtonItem.action;
id world = self.navigationItem.rightBarButtonItem.target;
[world performSelector:exit];
}
这里,
rightBarButtonItem
的类型是UIBarButtonItem
。
斯威夫特5:
class ViewController: UIViewController {
@IBOutlet weak var theTextfield: UITextField!
@IBOutlet weak var someButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
theTextfield.text = "Pwd"
someButton.sendActions(for: .touchUpInside)
}
@IBAction func someButtonTap(_ sender: UIButton) {
print("button tapped")
}
}
对于那些编写单元测试而无需 UI 测试的人来说很方便;-)
Swift 5 方法来解决
UIBarButtonItem
,它没有像 UIButton 等 sendAction
方法
extension UIBarButtonItem {
func sendAction() {
guard let myTarget = target else { return }
guard let myAction = action else { return }
let control: UIControl = UIControl()
control.sendAction(myAction, to: myTarget, for: nil)
}
}
现在您可以简单地:
let action = UIBarButtonItem(title: "title", style: .done, target: self, action: #selector(doSomething))
action.sendAction()
自 iOS 17.4 起,有一种方法可以以编程方式执行 UIControl 的主要操作:
func programmaticallyTriggerBtn() {
if #available(iOS 17.4, *) {
performPrimaryAction()
} else {
// Fallback on earlier versions
}
}
斯威夫特 4:
self.yourButton(self)