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?

Olie
źródło
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)

Olie
źródło
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)
Hellojeffy
źródło
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.

Jeff Kelley
źródło
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)
Gobi M.
źródło
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.

Hitesh Savaliya
źródło
jeśli używasz UIBarButtonItem, możesz po prostu [self doAction: self.navigationItem.rightBarButtonItem]; // - doAction: jest nazwą przełącznika self.navigationItem.rightBarButtonItem.
ok.
5

Dla systemu Xamarin iOS

btnObj.SendActionForControlEvents(UIControlEvent.TouchUpInside);

Odniesienie

Durai Amuthan.H
źródło
-3

Swift 4:

self .yourButton (self)

ELEMENTO Arts
źródło