Wie fälsche ich ein Touch-Ereignis programmgesteuert mit einem UIButton?


183

Ich schreibe einige Unit-Tests und aufgrund der Natur dieser speziellen App ist es wichtig, dass ich so hoch UIwie möglich in der Kette bin . Ich möchte also programmgesteuert einen Knopfdruck auslösen, als hätte der Benutzer den Knopf in der Taste gedrückt GUI.

(Ja, ja - ich könnte einfach den IBActionSelektor aufrufen, aber auch hier macht es die Art dieser speziellen App wichtig, dass ich den tatsächlichen Tastendruck vortäusche, so dass der IBActionüber die Taste selbst aufgerufen wird.)

Was ist die bevorzugte Methode dafür?


Können Sie erklären, warum es wichtig ist, dass Sie den Tastendruck vortäuschen, anstatt die Aktionsmethode direkt aufzurufen? Es gibt wirklich keinen praktischen Unterschied.
Jasarien

1
@ Jasarien: Nun, weil es einen Unterschied gibt! ;) In meiner App verwenden mehrere Schaltflächen dieselbe Aktionsmethode, und die Methode analysiert das Verhalten basierend auf dem Tag der Schaltfläche. Der Komponententest muss also zusätzlich zum Testen eines bestimmten Codepfads durch die Methode (a) alle testen und (b) auch überprüfen, ob die Tasten korrekt verdrahtet sind. Darüber hinaus wird meine Unit-Test-Suite gut abstrahiert, da ich Unit-Tests als Zeilen in einer Textdatei mit folgendem Wert definieren kann: "1 + 2 = 3" wobei "3" die erwartete Endanzeige ist und alles davor ist, welche Taste zu drücken ist.
Olie

Nun, hat Ihre Aktionsmethode keinen (ID-) Absenderparameter? Könnten Sie nicht einfach die Methode aufrufen und die Schaltfläche als Absender übergeben?
Jasarien

3
Aufgrund der abstrakten Natur meiner Testumgebung, kann ich nicht wissen , das Verfahren , dass der Bedarf für eine bestimmte Taste aufgerufen werden. Ich nehme an, ich könnte in die Schaltfläche graben und sie erhalten, aber sendActionsForControlEvents ausführen: erledigt dies alles für mich mit weniger Fehlermöglichkeiten und hält den Test abstrakt und passt zum Design.
Olie

Antworten:


459

Es stellt sich heraus, dass

[buttonObj sendActionsForControlEvents: UIControlEventTouchUpInside];

In diesem Fall habe ich genau das bekommen, was ich brauchte.

BEARBEITEN: Vergessen Sie nicht, dies im Hauptthread zu tun, um Ergebnisse zu erhalten, die einem Benutzerdruck ähneln.


Für Swift 3:

buttonObj.sendActions(for: .touchUpInside)


Was nicht anders ist als anrufen[myController myActionMethod:myButton1];
Jasarien

11
Sie haben große Zurückhaltung in Ihren Kommentarantworten;)
Dan Rosenstark

@Jasarien ist ganz anders, da es das Touch-Ereignis an alle registrierten Ziele (Listener) sendet.
Htafoya

2
Leider funktioniert keines von beiden immer - sie setzen voraus, dass der Empfänger ein UIControl ist, anstatt beispielsweise eine Tippgeste zu haben.
Tooluser

1
@ChenLiYong, Ein Grund wäre, wenn das myActionMethod:nicht öffentlich ist und Sie es daher nicht direkt aufrufen können.
Iulian Onofrei

50

Ein Update zu dieser Antwort für Swift

buttonObj.sendActionsForControlEvents(.TouchUpInside)

BEARBEITEN : Aktualisiert für Swift 3

buttonObj.sendActions(for: .touchUpInside)

1
Ich würde sagen, dass: buttonObj.sendActionsForControlEvents (.TouchUpInside) noch schneller Stil ist;)
Sajjon

1
Ich denke nicht, dass dies funktionieren wird, wenn die Schaltfläche in einem XCTestCase erstellt wird, ohne dass eine Run-Schleife unterstützt wird.
CopperCash

6

Wenn Sie diese Art von Tests durchführen möchten, werden Sie die UI-Automatisierungsunterstützung in iOS 4 lieben. Sie können JavaScript schreiben, um das Drücken von Tasten usw. ziemlich einfach zu simulieren, obwohl die Dokumentation (insbesondere der Teil mit den ersten Schritten) etwas ist spärlich.


1
Ja, das ist cooles Zeug, aber ich versuche es aus der App heraus zu machen, nicht über Instrumente (wenn das die Methode ist, die du meinst)
Olie

Instruments läuft mit Ihrer App. Die App läuft noch, Instruments simuliert nur das Berühren.
Jeff Kelley

6
Ich verstehe Instruments, Jeff - ich sage: Ich möchte, dass meine Unit-Tests im Gerät in meiner Tasche ausgeführt werden, ohne dass ein Laptop, XCode oder Instrumente zur Hand sind. Oder kennen Sie das Geheimnis, Instrumente auf dem Gerät laufen zu lassen? ;)
Olie

5

In diesem Fall UIButtonwird abgeleitet von UIControl. Dies funktioniert für Objekte, die von abgeleitet sindUIControl .

Ich wollte die UIBarButtonItemAktion " " für einen bestimmten Anwendungsfall wiederverwenden . Hier UIBarButtonItembietet keine MethodesendActionsForControlEvents:

Aber zum Glück UIBarButtonItemhat Eigenschaften für Ziel & Aktion.

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

Hier rightBarButtonItemist vom Typ UIBarButtonItem.


Wenn Sie UIBarButtonItem verwenden, können Sie einfach [self doAction: self.navigationItem.rightBarButtonItem]; // - doAction: ist der Umschaltaktionsname von self.navigationItem.rightBarButtonItem.
Am


5

Swift 3:

self.btn.sendActions(for: .touchUpInside)

3
Dies wiederholt nur die höher bewerteten Antworten.
Pang

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.