如何以编程方式伪造UIButton的触摸事件?

我正在编写一些单元测试,由于这个特定应用程序的性质,获得尽可能高的UI链非常重要。因此,我想做的是以编程方式触发按钮按下,就像用户按下GUI中的按钮一样。

(是的,是的--我__abc2只是调用__abc0选择器,但是,同样,这个特定应用程序的性质使得我必须伪造实际的按钮按下,以便从按钮本身调用__abc0。)

执行此操作的首选方法是什么?

113496 次浏览

If you want to do this kind of testing, you’ll love the UI Automation support in iOS 4. You can write JavaScript to simulate button presses, etc. fairly easily, though the documentation (especially the getting-started part) is a bit sparse.

It turns out that

[buttonObj sendActionsForControlEvents:UIControlEventTouchUpInside];

got me exactly what I needed, in this case.

EDIT: Don't forget to do this in the main thread, to get results similar to a user-press.


For Swift 3:

buttonObj.sendActions(for: .touchUpInside)

In this case, UIButton is derived from UIControl. This works for object derived from UIControl.

I wanted to reuse "UIBarButtonItem" action on specific use case. Here, UIBarButtonItem doesn't offer method sendActionsForControlEvents:

But luckily, UIBarButtonItem has properties for target & action.

 if(notHappy){
SEL exit = self.navigationItem.rightBarButtonItem.action;
id  world = self.navigationItem.rightBarButtonItem.target;
[world performSelector:exit];
}

Here, rightBarButtonItem is of type UIBarButtonItem.

An update to this answer for Swift

buttonObj.sendActionsForControlEvents(.TouchUpInside)

EDIT: Updated for Swift 3

buttonObj.sendActions(for: .touchUpInside)

For Xamarin iOS

btnObj.SendActionForControlEvents(UIControlEvent.TouchUpInside);

Reference

Swift 3:

self.btn.sendActions(for: .touchUpInside)

Swift 4:

self .yourButton(self)

It's handy for people who write Unit Tests without UI Tests ;-)

Swift 5 way to solve it for UIBarButtonItem, which does not have sendAction method like UIButton etc.

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)
}
}

And now you can simply:

let action = UIBarButtonItem(title: "title", style: .done, target: self, action: #selector(doSomething))
action.sendAction()

Swift 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")
}
}