jak programowo sfałszować zdarzenie dotykowe do przycisku UIB?


183

Piszę kilka testów jednostkowych, a ze względu na charakter tej konkretnej aplikacji ważne jest, aby uzyskać jak najwyższy poziom UIłańcucha. Tak więc, co chciałbym zrobić, to programowo uruchomić naciśnięcie przycisku, tak jakby użytkownik nacisnął przycisk w GUI.

(Tak, tak - mógłbym po prostu zadzwonić do IBActionselektora, ale znowu natura tej konkretnej aplikacji sprawia, że ​​ważne jest, aby sfałszować faktyczne naciśnięcie przycisku, tak aby IBActionwywołać go z samego przycisku.)

Jaka jest preferowana metoda tego?


Czy możesz wyjaśnić, dlaczego ważne jest, aby fałszować przycisk dotykowy, a nie bezpośrednio wywoływać metodę działania? Naprawdę nie ma praktycznej różnicy.
Jasarien

1
@Jararien: cóż, ponieważ istnieje różnica! ;) W mojej aplikacji kilka przycisków używa tej samej metody akcji, a metoda analizuje, jak się zachować na podstawie znacznika przycisku. Zatem test jednostkowy, oprócz testowania jednej konkretnej ścieżki kodu za pomocą metody, (a) musi przetestować je wszystkie, a (b) sprawdza również, czy przyciski są prawidłowo okablowane. Ponadto ładnie abstrahuje mój pakiet testów jednostkowych, ponieważ mogę zdefiniować testy jednostkowe jako linie w pliku tekstowym z czymś takim: „1 + 2 = 3”, gdzie „3” jest oczekiwanym końcowym wyświetlaniem i wszystko przed nim to przycisk, który należy nacisnąć.
Olie,

cóż, czy twoja metoda akcji nie ma parametru (id) nadawcy? Czy nie możesz po prostu wywołać metody i przekazać przycisk jako nadawca?
Jasarien

3
Ze względu na abstrakcyjny charakter mojej uprzęży testowej, NIE WIEM metody, która musi zostać wywołana dla określonego przycisku. Przypuszczam, że mógłbym zagłębić się w przycisk i pobrać go, ale wykonanie sendActionsForControlEvents: robi to wszystko dla mnie, z mniejszą szansą na błędy, i utrzymuje streszczenie testu i dopasowanie do projektu.
Olie,

Odpowiedzi:


459

Okazało się, że

[buttonObj sendActionsForControlEvents: UIControlEventTouchUpInside];

w tym przypadku dostałem dokładnie to, czego potrzebowałem.

EDYCJA: Nie zapomnij zrobić tego w głównym wątku, aby uzyskać wyniki podobne do naciśnięcia przez użytkownika.


W przypadku Swift 3:

buttonObj.sendActions(for: .touchUpInside)


Co nie różni się od dzwonienia[myController myActionMethod:myButton1];
Jasarien

11
masz wielką powściągliwość w odpowiedziach na komentarze;)
Dan Rosenstark,

@Jararien jest zupełnie inny, ponieważ wyśle ​​zdarzenie dotykowe do wszystkich zarejestrowanych celów (słuchaczy).
htafoya

2
Niestety, żadne z nich nie zawsze będzie działać - polegają one raczej na tym, że odbiornik jest kontrolerem UIC, niż np. Gestem dotknięcia.
tooluser

1
@ChenLiYong, Jednym z powodów byłby myActionMethod:brak publicznego, więc nie można zadzwonić bezpośrednio.
Iulian Onofrei

50

Aktualizacja tej odpowiedzi dla Swift

buttonObj.sendActionsForControlEvents(.TouchUpInside)

EDYCJA : Zaktualizowano dla Swift 3

buttonObj.sendActions(for: .touchUpInside)

1
Powiedziałbym, że: buttonObj.sendActionsForControlEvents (.TouchUpInside) ma jeszcze bardziej szybki styl;)
Sajjon

1
Nie sądzę, że to zadziała, jeśli przycisk zostanie utworzony w XCTestCase bez obsługi pętli uruchamiania.
CopperCash

6

Jeśli chcesz przeprowadzić tego rodzaju testy, spodoba ci się obsługa automatyzacji interfejsu w iOS 4. Możesz napisać JavaScript, aby symulować naciskanie przycisków itp. Dość łatwo, chociaż dokumentacja (szczególnie część wprowadzająca) jest nieco rzadki.


1
Tak, to fajne rzeczy, ale staram się to robić z poziomu aplikacji, a nie za pomocą Instrumentów (jeśli masz na myśli metodę).
Olie,

Instrumenty działają z Twoją aplikacją. Aplikacja nadal działa, Instruments po prostu symuluje dotyk.
Jeff Kelley,

6
Rozumiem Instruments, Jeff - mówię: chcę, aby moje testy jednostkowe działały w urządzeniu w kieszeni, bez laptopa, XCode'a lub Instrumentów. A może znasz sekret obsługi instrumentów na urządzeniu? ;)
Olie,

6

Swift 3:

self.btn.sendActions(for: .touchUpInside)

3
To tylko powtórzenie wyżej ocenianych odpowiedzi.
Pang

5

W tym przypadku UIButtonpochodzi od UIControl. Działa to dla obiektu pochodzącego z UIControl.

Chciałem ponownie użyć UIBarButtonItemakcji „ ” w konkretnym przypadku użycia. Tutaj UIBarButtonItemnie oferuje metodysendActionsForControlEvents:

Ale na szczęście UIBarButtonItemma właściwości do celu i działania.

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

Tutaj rightBarButtonItemjest typu UIBarButtonItem.


jeśli używasz UIBarButtonItem, możesz po prostu [self doAction: self.navigationItem.rightBarButtonItem]; // - doAction: jest nazwą przełącznika self.navigationItem.rightBarButtonItem.
ok.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.