come falsificare programmaticamente un evento touch su un UIButton?


183

Sto scrivendo alcuni test unitari e, a causa della natura di questa particolare app, è importante arrivare il più in alto UIpossibile nella catena. Quindi, ciò che mi piacerebbe fare è attivare a livello di programmazione una pressione del pulsante, come se l'utente avesse premuto il pulsante in GUI.

(Sì, sì - potrei semplicemente chiamare il IBActionselettore ma, ancora una volta, la natura di questa particolare app rende importante che falsi l'effettiva pressione del pulsante, in modo tale che IBActionvenga chiamato dal pulsante stesso.)

Qual è il metodo preferito per farlo?


Potresti spiegare perché è importante falsificare il tocco del pulsante anziché chiamare direttamente il metodo di azione? Non c'è davvero alcuna differenza pratica.
Jasarien,

1
@Jasarien: beh, perché c'è una differenza! ;) Nella mia app, diversi pulsanti utilizzano lo stesso metodo di azione e il metodo analizza il comportamento in base al tag del pulsante. Quindi il test unitario, oltre a testare un particolare percorso di codice attraverso il metodo, (a) deve testarli tutti e (b) verifica anche che i pulsanti siano collegati correttamente. Inoltre, riassume perfettamente la mia suite di test di unità, poiché posso definire i test di unità come linee in un file di testo con qualcosa del genere: "1 + 2 = 3" dove "3" è la visualizzazione finale prevista e tutto ciò che lo precede è quale pulsante premere.
Olie,

bene il tuo metodo di azione non ha un parametro (id) mittente? Non potresti semplicemente chiamare il metodo e passare il pulsante come mittente?
Jasarien,

3
A causa della natura astratta del mio cablaggio di prova, non CONOSCO il metodo che deve essere chiamato per un pulsante particolare. Suppongo che potrei scavare nel pulsante e ottenerlo, ma facendo sendActionsForControlEvents: fa tutto questo per me, con meno opportunità di errore e mantiene astratto il test e si adatta al design.
Olie,

Risposte:


459

Si scopre che

[buttonObj sendActionsForControlEvents: UIControlEventTouchUpInside];

mi ha procurato esattamente ciò di cui avevo bisogno, in questo caso.

EDIT: non dimenticare di farlo nel thread principale, per ottenere risultati simili a quelli di un utente.


Per Swift 3:

buttonObj.sendActions(for: .touchUpInside)


Il che non è diverso dal chiamare[myController myActionMethod:myButton1];
Jasarien il

11
hai una grande moderazione nelle risposte ai tuoi commenti;)
Dan Rosenstark il

@Jasarien è abbastanza diverso, in quanto invierà l'evento touch a tutti i target registrati (ascoltatori).
htafoya,

2
Sfortunatamente, nessuno di questi funzionerà sempre: si basano sul fatto che il ricevitore è un UIControl, anziché ad esempio con un gesto di tocco.
tooluser,

1
@ChenLiYong, Uno dei motivi sarebbe se myActionMethod:non è pubblico, quindi non puoi chiamarlo direttamente.
Iulian Onofrei,

50

Un aggiornamento a questa risposta per Swift

buttonObj.sendActionsForControlEvents(.TouchUpInside)

EDIT : aggiornato per Swift 3

buttonObj.sendActions(for: .touchUpInside)

1
Direi che: buttonObj.sendActionsForControlEvents (.TouchUpInside) è ancora più stile Swift;)
Sajjon,

1
Non penso che funzionerà se il pulsante viene creato in un XCTestCase senza supporto per il ciclo di esecuzione.
CopperCash

6

Se vuoi fare questo tipo di test, ti piacerà il supporto dell'automazione dell'interfaccia utente in iOS 4. Puoi scrivere JavaScript per simulare abbastanza facilmente la pressione dei pulsanti, ecc., Sebbene la documentazione (specialmente la parte iniziale) sia un po ' sparse.


1
Sì, è roba interessante, ma sto provando a farlo dall'app, non tramite Instruments (se questo è il metodo che intendi).
Olie

Instruments funziona con la tua app. L'app è ancora in esecuzione, Instruments simula solo il tocco.
Jeff Kelley,

6
Capisco Instruments, Jeff - quello che sto dicendo è: voglio che i miei test unitari vengano eseguiti nel dispositivo in tasca, senza un laptop o un XCode o strumenti a portata di mano. O conosci il segreto degli strumenti da corsa sul dispositivo? ;)
Olie,

6

Swift 3:

self.btn.sendActions(for: .touchUpInside)

3
Questo è solo ripetere le risposte con il punteggio più alto.
Provò il

5

In questo caso, UIButtonè derivato da UIControl. Funziona con oggetti derivati ​​da UIControl.

Volevo riutilizzare " UIBarButtonItem" l'azione su un caso d'uso specifico. Qui, UIBarButtonItemnon offre metodosendActionsForControlEvents:

Ma per fortuna, UIBarButtonItemha proprietà per bersaglio e azione.

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

Ecco, rightBarButtonItemè di tipo UIBarButtonItem.


se usi UIBarButtonItem, puoi semplicemente [self doAction: self.navigationItem.rightBarButtonItem]; // - doAction: is self.navigationItem.rightBarButtonItem è il nome dell'azione di attivazione / disattivazione.
rievocazione del


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.