como falsificar programaticamente um evento de toque em um UIButton?


183

Estou escrevendo alguns testes de unidade e, devido à natureza desse aplicativo em particular, é importante que eu suba no nível UI possível cadeia. Então, o que eu gostaria de fazer é acionar programaticamente um pressionamento de botão, como se o usuário tivesse pressionado o botão no GUI.

(Sim, sim - eu poderia simplesmente chamar oIBAction seletor, mas, novamente, a natureza desse aplicativo em particular torna importante que eu falsifique o pressionamento real do botão, de modo que IBActionseja chamado pelo próprio botão.)

Qual é o método preferido para fazer isso?


Você poderia explicar por que é importante falsificar o toque do botão em vez de chamar o método de ação diretamente? Realmente não há diferença prática.
Jasarien 27/10/10

1
@ Jasarien: bem, porque há uma diferença! ;) No meu aplicativo, vários botões usam o mesmo método de ação, e o método analisa como se comportar com base na tag do botão. Portanto, o teste de unidade, além de testar um caminho de código específico através do método, (a) precisa testá-los todos e (b) também verifica se os botões estão conectados corretamente. Além disso, ele abstrai bem o meu conjunto de testes de unidade, pois eu posso definir testes de unidade como linhas em um arquivo de texto com algo como isto: "1 + 2 = 3" onde "3" é a exibição final esperada e tudo o que está antes é qual botão apertar.
Olie

bem, seu método de ação não possui um parâmetro de emissor (id)? Você não poderia simplesmente chamar o método e passar o botão como remetente?
Jasarien 27/10/10

3
Devido à natureza abstrata do meu equipamento de teste, não sei o método que precisa ser chamado para um botão específico. Suponho que eu poderia cavar o botão e obtê-lo, mas enviar sendActionsForControlEvents: faz tudo isso para mim, com menos oportunidade de erro, e mantém o teste abstrato e adequado ao design.
Olie

Respostas:


459

Acontece que

[buttonObj sendActionsForControlEvents: UIControlEventTouchUpInside];

me deu exatamente o que eu precisava, neste caso.

EDIT: Não se esqueça de fazer isso no thread principal, para obter resultados semelhantes aos da imprensa do usuário.


Para o Swift 3:

buttonObj.sendActions(for: .touchUpInside)


O que não é diferente de chamar[myController myActionMethod:myButton1];
Jasarien 27/10/10

11
você tem muita restrição nas respostas aos seus comentários;) #
455 Dan Rosenstark

O @Jasarien é bem diferente, pois enviará o evento de toque a todos os alvos registrados (ouvintes).
Htafoya

2
Infelizmente, nenhum deles funcionará sempre - eles confiam no receptor como um UIControl, em vez de, por exemplo, ter um gesto de toque.
tooluser

1
@ChenLiYong, Uma razão seria se myActionMethod:não for pública e, portanto, você não pode chamá-lo diretamente.
Iulian Onofrei 22/03

50

Uma atualização para esta resposta para Swift

buttonObj.sendActionsForControlEvents(.TouchUpInside)

EDIT : Atualizado para Swift 3

buttonObj.sendActions(for: .touchUpInside)

1
Eu diria que: buttonObj.sendActionsForControlEvents (.TouchUpInside) é ainda mais estilo Swift;)
Sajjon

1
Eu não acho que isso funcionará se o botão for criado em um XCTestCase sem um loop de execução compatível.
CopperCash

6

Se você deseja fazer esse tipo de teste, adorará o suporte à UI Automation no iOS 4. Você pode escrever JavaScript para simular pressionamentos de botão, etc. com bastante facilidade, embora a documentação (especialmente a parte de introdução) seja um pouco escasso.


1
Sim, isso é legal coisas, mas eu estou tentando fazê-lo de dentro do aplicativo, não via Instruments (se esse é o método que você quer dizer.)
Olie

O Instruments é executado com seu aplicativo. O aplicativo ainda está sendo executado, o Instruments simula o toque.
Jeff Kelley

6
Entendo a Instruments, Jeff - o que estou dizendo é: quero que meus testes de unidade sejam executados no dispositivo no meu bolso, sem um laptop, XCode ou Instruments à mão. Ou você conhece o segredo de executar instrumentos no dispositivo? ;)
Olie

6

Swift 3:

self.btn.sendActions(for: .touchUpInside)

3
Isso está apenas repetindo as respostas mais pontuadas.
Pang

5

Nesse caso, UIButtoné derivado de UIControl. Isso funciona para o objeto derivado de UIControl.

Queria reutilizar " UIBarButtonItem" ações em casos de uso específicos. Aqui, UIBarButtonItemnão oferece métodosendActionsForControlEvents:

Mas, felizmente, UIBarButtonItempossui propriedades para destino e ação.

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

Aqui, rightBarButtonItemé do tipo UIBarButtonItem.


se você usar UIBarButtonItem, poderá apenas [self doAction: self.navigationItem.rightBarButtonItem]; // - doAction: é o nome da ação de alternância de self.navigationItem.rightBarButtonItem.
c0ming


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.