Как программно подделать сенсорное событие для UIButton?

183

Я пишу некоторые юнит-тесты, и, учитывая характер этого конкретного приложения, важно, чтобы я поднялся UIкак можно выше. Итак, что я хотел бы сделать, это программно вызвать нажатие кнопки, как если бы пользователь нажал кнопку в GUI.

(Да, да - я мог бы просто вызвать IBActionселектор, но, опять же, характер этого конкретного приложения делает важным, чтобы я имитировал фактическое нажатие кнопки, чтобы сам IBActionвызов вызывался с кнопки.)

Какой предпочтительный способ сделать это?

Olie
источник
Не могли бы вы объяснить, почему важно подделывать касание кнопки, а не вызывать метод действия напрямую? Там действительно нет практической разницы.
Jasarien
1
@Jasarien: ну, потому что есть разница! ;) В моем приложении несколько кнопок используют один и тот же метод действия, и этот метод анализирует поведение на основе тега кнопки. Таким образом, модульное тестирование, в дополнение к тестированию одного конкретного пути кода с помощью метода, (а) должно проверить их все и (б) также проверяет, правильно ли подключены кнопки. Кроме того, он прекрасно абстрагирует мой набор модульных тестов, так как я могу определить модульные тесты как строки в текстовом файле с чем-то таким: это какая кнопка нажать.
Оли
ну разве у вашего метода действия нет параметра (id) sender? Не могли бы вы просто вызвать метод и передать кнопку в качестве отправителя?
Jasarien
3
Из-за абстрактной природы моего тестового жгута я не ЗНАЮ метод, который нужно вызывать для конкретной кнопки. Я полагаю, что мог бы покопаться в кнопке и получить ее, но выполнение sendActionsForControlEvents: делает все это для меня, с меньшей вероятностью ошибки, и держит тест абстрактным и соответствующим дизайну.
Olie

Ответы:

459

Оказывается, что

[buttonObj sendActionsForControlEvents: UIControlEventTouchUpInside];

получил именно то, что мне было нужно, в данном случае.

РЕДАКТИРОВАТЬ: не забудьте сделать это в основной теме, чтобы получить результаты, аналогичные нажатию пользователя.


Для Swift 3:

buttonObj.sendActions(for: .touchUpInside)

Olie
источник
Что ничем не отличается от звонка[myController myActionMethod:myButton1];
Jasarien
11
Вы очень сдержаны в своих комментариях;)
Дэн Розенстарк
@Jasarien совсем другой, так как он отправит событие касания всем зарегистрированным целям (слушателям).
Хтафоя
2
К сожалению, ни один из них не всегда будет работать - они полагаются на то, что получатель является UIControl, а не, например, имеет жест касания.
Tooluser
1
@ChenLiYong, одна из причин может быть, если myActionMethod:не является публичной, и поэтому вы не можете позвонить напрямую.
Юлиан Онофрей
50

Обновление к этому ответу для Swift

buttonObj.sendActionsForControlEvents(.TouchUpInside)

РЕДАКТИРОВАТЬ : Обновлено для Swift 3

buttonObj.sendActions(for: .touchUpInside)
Hellojeffy
источник
1
Я бы сказал, что: buttonObj.sendActionsForControlEvents (.TouchUpInside) еще более быстрый стиль;)
Саджон
1
Я не думаю, что это будет работать, если кнопка будет создана в XCTestCase без поддержки цикла выполнения.
CopperCash
6

Если вы хотите проводить такого рода тестирование, вам понравится поддержка автоматизации пользовательского интерфейса в iOS 4. Вы можете написать JavaScript для имитации нажатия кнопок и т. Д. Довольно легко, хотя документация (особенно часть с самого начала) немного скудны.

Джефф Келли
источник
1
Да, это классная штука, но я пытаюсь сделать это из приложения, а не с помощью инструментов (если вы имеете в виду метод).
Olie
Инструменты работают с вашим приложением. Приложение все еще работает, инструменты просто имитируют прикосновения.
Джефф Келли
6
Я понимаю Instruments, Джефф - я говорю следующее: я хочу, чтобы мои модульные тесты выполнялись в устройстве в моем кармане, без ноутбука, XCode или Instruments. Или вы знаете секрет работы приборов на устройстве? ;)
Оли
6

Свифт 3:

self.btn.sendActions(for: .touchUpInside)
Гоби М
источник
3
Это просто повторение ответов с более высокими оценками.
Пан
5

В этом случае UIButtonпроисходит от UIControl. Это работает для объекта, полученного из UIControl.

Я хотел повторно использовать UIBarButtonItemдействие для конкретного случая использования. Здесь UIBarButtonItemне предлагает методsendActionsForControlEvents:

Но, к счастью, UIBarButtonItemимеет свойства для цели и действия.

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

Здесь, rightBarButtonItemимеет тип UIBarButtonItem.

Хитеш Савалия
источник
если вы используете UIBarButtonItem, вы можете просто [self doAction: self.navigationItem.rightBarButtonItem]; // - doAction: является именем действия переключения self.navigationItem.rightBarButtonItem.
c0ming
-3

Свифт 4:

self .yourButton (self)

ЭЛЕМЕНТО Искусство
источник