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?

Olie
quelle
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)

Olie
quelle
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)
Hallojeffy
quelle
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.

Jeff Kelley
quelle
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.

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

Für Xamarin iOS

btnObj.SendActionForControlEvents(UIControlEvent.TouchUpInside);

Referenz

Durai Amuthan.H
quelle
5

Swift 3:

self.btn.sendActions(for: .touchUpInside)
Gobi M.
quelle
3
Dies wiederholt nur die höher bewerteten Antworten.
Pang
-2

Swift 4:

self .yourButton (self)

ELEMENTO Arts
quelle