comment simuler par programmation un événement tactile en UIButton?


187

J'écris des tests unitaires et, en raison de la nature de cette application particulière, il est important que je monte le plus haut possible dans la UIchaîne. Donc, ce que j'aimerais faire, c'est déclencher par programme une pression sur un bouton, comme si l'utilisateur avait appuyé sur le bouton dans le GUI.

(Oui, oui - je pourrais simplement appeler le IBActionsélecteur mais, encore une fois, la nature de cette application particulière fait qu'il est important que je simule la pression réelle du bouton, de sorte que l' IBActionappel soit appelé à partir du bouton lui-même.)

Quelle est la méthode préférée pour faire cela?


Pourriez-vous expliquer pourquoi il est important de simuler le toucher du bouton plutôt que d'appeler directement la méthode d'action? Il n'y a vraiment aucune différence pratique.
Jasarien

1
@Jasarien: eh bien, car il y a une différence! ;) Dans mon application, plusieurs boutons utilisent la même méthode d'action, et la méthode analyse comment se comporter en fonction de la balise du bouton. Ainsi, le test unitaire, en plus de tester un chemin de code particulier à travers la méthode, (a) doit les tester tous et (b) vérifie également que les boutons sont correctement câblés. De plus, cela résume joliment ma suite de tests unitaires, car je peux définir les tests unitaires comme des lignes dans un fichier texte avec quelque chose comme ceci: "1 + 2 = 3" où "3" est l'affichage final attendu, et tout ce qui se trouve avant est quel bouton appuyer.
Olie

votre méthode d'action n'a-t-elle pas un paramètre d'expéditeur (id)? Ne pourriez-vous pas simplement appeler la méthode et passer le bouton en tant qu'expéditeur?
Jasarien

3
En raison de la nature abstraite de mon harnais de test, je ne SAIS la méthode qui doit être appelé à un bouton particulier. Je suppose que je pourrais creuser dans le bouton et l'obtenir, mais faire sendActionsForControlEvents: fait tout cela pour moi, avec moins de possibilités d'erreur, et garde le test abstrait et adapté à la conception.
Olie

Réponses:


465

Il se trouve que

[buttonObj sendActionsForControlEvents: UIControlEventTouchUpInside];

m'a donné exactement ce dont j'avais besoin, dans ce cas.

EDIT: N'oubliez pas de le faire dans le fil de discussion principal, pour obtenir des résultats similaires à ceux d'une presse utilisateur.


Pour Swift 3:

buttonObj.sendActions(for: .touchUpInside)


Ce qui n'est pas différent d'appeler[myController myActionMethod:myButton1];
Jasarien

11
vous avez une grande retenue dans vos réponses aux commentaires;)
Dan Rosenstark

@Jasarien est assez différent, car il enverra l'événement tactile à toutes les cibles enregistrées (auditeurs).
htafoya

2
Malheureusement, ni l'un ni l'autre ne fonctionnera toujours - ils reposent sur le fait que le récepteur est un UIControl, plutôt que d'avoir par exemple un geste de tapotement.
tooluser

1
@ChenLiYong, une des raisons serait si le myActionMethod:n'est pas public, et vous ne pouvez donc pas l'appeler directement.
Iulian Onofrei

52

Une mise à jour de cette réponse pour Swift

buttonObj.sendActionsForControlEvents(.TouchUpInside)

EDIT : mis à jour pour Swift 3

buttonObj.sendActions(for: .touchUpInside)

1
Je dirais que: buttonObj.sendActionsForControlEvents (.TouchUpInside) est encore plus de style Swift;)
Sajjon

1
Je ne pense pas que cela fonctionnera si le bouton est créé dans un XCTestCase sans prise en charge de la boucle d'exécution.
CopperCash

8

Swift 3:

self.btn.sendActions(for: .touchUpInside)

3
Ceci ne fait que répéter les réponses les mieux notées.
Pang

6

Si vous voulez faire ce type de test, vous adorerez le support UI Automation dans iOS 4. Vous pouvez écrire du JavaScript pour simuler les pressions sur des boutons, etc. assez facilement, bien que la documentation (en particulier la partie de démarrage) soit un peu clairsemé.


1
Ouais, c'est cool, mais j'essaye de le faire depuis l'application, pas via Instruments (si c'est la méthode que tu veux dire.)
Olie

Les instruments fonctionnent avec votre application. L'application est toujours en cours d'exécution, Instruments simule simplement le toucher.
Jeff Kelley

6
Je comprends les instruments, Jeff - ce que je dis, c'est: je veux que mes tests unitaires s'exécutent dans l'appareil dans ma poche, sans ordinateur portable ni XCode ou Instruments à portée de main. Ou connaissez-vous le secret de l'exécution d'instruments sur l'appareil? ;)
Olie

5

Dans ce cas, UIButtonest dérivé de UIControl. Cela fonctionne pour les objets dérivés de UIControl.

Je voulais réutiliser l' UIBarButtonItemaction " " sur un cas d'utilisation spécifique. Ici, UIBarButtonItemn'offre pas de méthodesendActionsForControlEvents:

Mais heureusement, UIBarButtonItema des propriétés pour la cible et l'action.

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

Ici, rightBarButtonItemc'est de type UIBarButtonItem.


si vous utilisez UIBarButtonItem, vous pouvez simplement [self doAction: self.navigationItem.rightBarButtonItem]; // - doAction: est le nom de l'action de basculement de self.navigationItem.rightBarButtonItem.
c0ming


1

C'est pratique pour les personnes qui écrivent des tests unitaires sans tests d'interface utilisateur ;-)

Swift 5 façon de le résoudre UIBarButtonItem, qui n'a pas de sendActionméthode comme 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)
    }
}

Et maintenant, vous pouvez simplement:

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.