Xctest waitforexpectationswithtimeout
Estou testando uma chamada assíncrona usando o XCTestExpectation.
O código a seguir funciona (o teste é bem-sucedido) quando o completionHandler é executado antes do tempo limite especificado de 1 segundo.
No entanto, se o completionHandler não for chamado e, portanto, a expectativa não for atendida, em vez de obter uma falha de teste ao chamar waitForExpectationsWithTimeout, recebo um EXC_BAD_ACCESS, o que não é muito útil, pois isso impossibilita a visualização dos resultados do conjunto de testes.
Como posso evitar isso e obter uma falha normal no teste?
Xctest waitforexpectationswithtimeout
Estou usando os novos recursos de teste assíncrono do Xcode 6. Tudo funciona bem quando a tarefa assíncrona termina antes do tempo limite. Mas se a tarefa demorar mais que o tempo limite, as coisas ficam mais complicadas.
Aqui está como estou fazendo meus testes:
Infelizmente, ao chamar o método de preenchimento após o tempo limite ter expirado, a suíte de testes é paralisada com este erro:
Violação da API - chamada - [XCTestExpectation fulfill] após o término do contexto de espera.
É claro que posso verificar se o teste terminou antes de chamar o método de preenchimento assim:
Mas isso parece muito complicado e torna o teste muito mais difícil de ler. Estou esquecendo de algo? Existe uma maneira mais simples de resolver este problema?
Sim, há uma maneira muito mais simples de evitar esse problema de violação da API: apenas declare sua variável de expectativa como __weak. Embora não esteja claramente documentada, a expectativa será liberada quando o tempo limite expirar. Portanto, se a tarefa demorar mais do que o tempo limite, a variável de expectativa será nula quando o manipulador de conclusão da tarefa for chamado. Assim, o método de preenchimento será chamado nulo, sem fazer nada.
Eu me deparei com o mesmo problema, mas no meu caso eu precisava da versão Swift da resposta acima.
Eu estou trabalhando em um OpenStack Swift Drive para OSX. Quando uma pasta é excluída localmente com o Finder, a exclusão eventualmente se propaga para o servidor, eu precisava de um teste que aguarda a atualização do servidor.
Para evitar a falha da violação da API, mudei minhas expectativas para "weak var" e mudei a chamada para preenchê-la para "zeroFoldersExpectation?.fulfill ()" com o extra "?" como a expectativa agora é opcional e pode se tornar nula, caso em que a chamada de preenchimento é ignorada. Isso corrigiu as falhas.
Em vez de criar expectativa como variável fraca (como sugerido nesta resposta), acho que você também pode definir como variável de bloco e nada no manipulador de conclusão de waitForExpectationsWithTimeout:
Desta forma, você tem certeza de que o ARC não irá lidar com expectativas muito rapidamente.
Assistentes Personalizados no XCTest.
À medida que sua suíte de testes cresce, é importante manter seu código DRY. Ou, não se repita. Você não implementaria o mesmo método três vezes em seu código de produção, então por que fazer isso em seus testes?
Uma maneira fácil de manter a qualidade no seu conjunto de testes é compartilhar asserções entre os testes. Isso pode ser feito extraindo métodos auxiliares para executar asserções comuns.
Por exemplo, no teste da interface do usuário, esperar que os elementos apareçam é bastante detalhado. Não quero escrever isso mais de uma vez se puder evitá-lo.
Vamos analisar um método que aguarda a exibição de um elemento.
Ótimo! Agora podemos apenas chamar waitForElementToAppear (app. cells [& quot; Joe & quot;]) e nosso ajudante cuidará do resto. O que acontece quando o teste falha?
Oh, espere, isso não é bom. Eu quero que a mensagem de falha seja tão próxima da linha de código que eu escrevi quanto possível.
Pense nisso como se você estivesse escrevendo um framework. Você gostaria de forçar seus usuários a pesquisar o código interno da estrutura apenas para ver uma mensagem de erro? Não, claro que não. Vamos mover essa mensagem para mais perto do teste real.
Esta postagem foi atualizada para o Swift 2.2. Para suporte ao Swift 2.1, substitua #file por __FILE__ e #line por __LINE__.
Aqui estamos aproveitando a substituição de falha manual com recordFailureWithDescription (). Isso recebe uma mensagem de falha, referência de arquivo, número de linha e um booleano.
mensagem: a cópia que o usuário verá quando o teste falhar no arquivo: uma referência ao arquivo em que a falha foi originalmente gravada: uma referência ao número da linha em que a falha foi originalmente registrada como esperado: true para falhas de teste e false para não detectado exceções.
O manipulador é chamado o tempo todo e não depende de a afirmação ter falhado ou não. Quando a verificação falha, o parâmetro de erro é preenchido. Por isso, precisamos garantir que ela esteja presente para reprovar nosso teste.
Os parâmetros de arquivo e linha são onde a mágica acontece. Ao especificá-los como opcionais, o chamador não é obrigado a passar nada. E, por padrão, as macros #file e #line podem capturar esses atributos na origem; onde nossos métodos estão sendo chamados. O blog do Swift tem um post incrível sobre como a Apple criou o assert () no Swift.
Muito melhor. Agora podemos adicionar métodos auxiliares ao conteúdo do nosso coração! Podemos continuar passando esses parâmetros pela cadeia e criar uma estrutura de testes altamente abstrata construída no XCTest.
Esperando no XCTest.
Esperar é difícil e esperar no Xcode não é exceção. Até mesmo escolher entre a infinidade de opções oferecidas pelo Xcode e pelo XCTest pode ser difícil. Continue lendo para aprender uma abordagem fácil e direta para esperar por novas classes introduzidas no Xcode 8.3.
Antes do Xcode 8.3.
O Xcode 7 introduziu uma série de novos métodos para ajudar a testar o código assíncrono, a saber, waitForExpectations (timeout: handler :). Este método pode ser usado para, bem, esperar pelas expectativas.
Um XCTestExpectation é uma classe XCTest que avalia continuamente uma expressão até que ela seja atendida ou o tempo limite seja atingido. Eles podem ser usados para esperar que as animações terminem, que elementos apareçam ou até mesmo que os valores-chave sejam alterados via KVO.
Aqui está um breve exemplo da minha postagem de teste de interface do usuário.
Este código é usado em um teste de interface do usuário para esperar que um elemento específico apareça na tela. Você passa no XCUIElement e o ajudante tenta encontrar o elemento por cinco segundos.
O ajudante waitForExpectations é ótimo, mas vem com uma ressalva. Ele gera uma exceção e falha no teste se o tempo limite for atingido. Isso limita sua funcionalidade a casos em que sabemos absolutamente que as expectativas serão atendidas.
O manipulador de conclusão de expectativa.
Tome nota de que passei nil para o parâmetro handler: no exemplo de código.
manipulador: Um bloco XCWaitCompletionHandler opcional para invocar quando todas as expectativas tiverem sido atendidas ou quando o tempo limite de espera for acionado. (O tempo limite é sempre tratado como uma falha de teste.)
E esse manipulador é um alias simples para envolver um erro opcional em um bloco.
Um bloco a ser chamado quando uma chamada para waitForExpectations (timeout: handler: tem todas as expectativas atendidas ou tempo limite esgotado).
typealias XCWaitCompletionHandler = (Erro?) - & gt; Vazio.
À primeira vista, essa definição é empolgante, é fácil inferir que o erro conterá todo tipo de informação útil. No entanto, na prática, não é esse o caso. Muito raramente foi algo mais do que um erro genérico sem descrição (localizada). рџ˜ћ.
Para nossa sorte, o Xcode 8.3 adicionou algumas novas classes e ajudantes para tornar a compreensão do motivo da falha um pouco mais fácil de entender.
O restante deste post faz referência à nova funcionalidade introduzida no Xcode 8.3 Beta.
Digite XCTestWaiter.
Gerencia a espera - pausando o contexto de execução atual - para uma matriz XCTestExpectations. Os garçons podem ser usados com ou sem um representante para responder a eventos como conclusão, tempo limite ou cumprimento de expectativa inválido. O XCTestCase está em conformidade com o protocolo delegado e relatará automaticamente os tempos limite e outros eventos inesperados como falhas de teste.
Os garçons podem ser usados sem um representante ou qualquer associação com uma instância de caso de teste. Isso permite que bibliotecas de suporte de teste forneçam métodos convenientes para aguardar sem precisar passar casos de teste por meio dessas APIs.
À primeira vista, o XCTestWaiter é simplesmente uma nova abordagem para esperar que o XCTestExpectation seja cumprido. No entanto, existem algumas gemas escondidas abaixo da superfície.
Primeiro, vamos converter a tag "old" amostra para usar a nova classe.
wait (for: timeout :) retorna um XCTestWaiterResult, um enum representando o resultado do teste. Pode ser um dos quatro valores possíveis: concluído, timedOut, incorrectOrder ou invertedFulfillment. Somente o primeiro, concluído, indica que o elemento foi encontrado com sucesso dentro do tempo limite alocado.
Uma grande vantagem dessa abordagem é que o conjunto de testes é lido como um fluxo síncrono. Não há bloco de retorno de chamada ou manipulador de conclusão. O método auxiliar simplesmente retorna um booleano, indicando se o elemento apareceu ou não.
Expectativas não cumpridas não falhar automaticamente…
Na minha opinião, esta é a maior melhoria para o quadro. Você está agora completamente no controle de quando e como falhar em seus testes se uma expectativa não for cumprida. Isso permite esperar por elementos opcionais, como uma tela de login ou uma caixa de diálogo de autorização de serviços de localização.
Você também pode dividir cada tipo de XCTestWaiterResult e reprová-los com mensagens de erro individuais. Por exemplo,.timedOut pode mencionar quanto tempo o tempo limite estava incorreto, enquanto o ORDER pode usar as Expectativas realizadas para anotar quais foram bem-sucedidas e quais ainda estamos aguardando.
Múltiplas Expectativas
Mais de um XCTestExpectation pode ser passado para o garçom, que pode ser usado em dois cenários diferentes.
Quaisquer das expectativas precisam ser atendidas - assim que um é atendido, o garçom para de esperar. Todas as expectativas precisam ser atendidas - o garçom continua a esperar até que todas estejam preenchidas.
Para indicar que todas as expectativas importam, simplesmente chame wait (for: timeout: enforceOrder :). O último parâmetro indicará ao framework se a ordem de atendimento também é importante.
Novas subclasses de XCTestExpectation.
Juntamente com a nova classe de garçons, o XCTestExpectations foi subclassificado para tornar as expectativas específicas um pouco mais fáceis de serem escritas. Sugiro usá-las sempre que possível, a legibilidade ajuda muito a escrever um conjunto de testes de manutenção.
XCTPredicateExpectation.
XCTKVOExpectation.
XCTNSNotificationExpectation.
Eu não consigo fazer isso funcionar. Se alguém tiver sucesso com esta subclasse, por favor me avise nos comentários.
Obrigado pela ajuda, Brian!
Xcode 8.4 e Beyond.
É reconfortante ver a Apple reinvestindo em sua estrutura de testes; não há muita atividade no XCTest desde sua renovação no Xcode 7. Estou ansioso para experimentar algo novo que venha com o próximo lançamento!
wait For Expectations With Timeout: manipulador:
Aguarda até que todas as expectativas sejam atendidas ou o tempo limite seja atingido.
Declaração.
Parâmetros
A quantidade de tempo em que todas as expectativas devem ser atendidas.
Um bloco opcional do Manipulador de Conclusão do XCWait para invocar quando todas as expectativas tiverem sido atendidas ou quando o tempo limite de espera for acionado. (O tempo limite é sempre tratado como uma falha de teste.)
Discussão.
Este método cria um ponto de sincronização no fluxo de um teste. Apenas uma espera Por Expectativas Com Tempo Limite: manipulador: pode estar ativo a qualquer momento, mas várias sequências discretas de "criam expectativas e esperam que elas sejam atendidas". podem ser encadeados juntos.
Este método aguarda as expectativas criadas apenas com os métodos de conveniência do XCTest Case. Esse método não espera as expectativas criadas manualmente por meio de inicializadores no XCTest Expectation ou em suas subclasses.
Para aguardar expectativas criadas manualmente, use a opção esperar por expectativas: tempo limite: ou espere por expectativas: tempo limite: impor ordem: métodos ou os métodos correspondentes no XCTWaiter, passando uma lista explícita de expectativas.
Os clientes não devem manipular o loop de execução enquanto usam esta API.
Estou usando os novos recursos de teste assíncrono do Xcode 6. Tudo funciona bem quando a tarefa assíncrona termina antes do tempo limite. Mas se a tarefa demorar mais que o tempo limite, as coisas ficam mais complicadas.
Aqui está como estou fazendo meus testes:
Infelizmente, ao chamar o método de preenchimento após o tempo limite ter expirado, a suíte de testes é paralisada com este erro:
Violação da API - chamada - [XCTestExpectation fulfill] após o término do contexto de espera.
É claro que posso verificar se o teste terminou antes de chamar o método de preenchimento assim:
Mas isso parece muito complicado e torna o teste muito mais difícil de ler. Estou esquecendo de algo? Existe uma maneira mais simples de resolver este problema?
Sim, há uma maneira muito mais simples de evitar esse problema de violação da API: apenas declare sua variável de expectativa como __weak. Embora não esteja claramente documentada, a expectativa será liberada quando o tempo limite expirar. Portanto, se a tarefa demorar mais do que o tempo limite, a variável de expectativa será nula quando o manipulador de conclusão da tarefa for chamado. Assim, o método de preenchimento será chamado nulo, sem fazer nada.
Eu me deparei com o mesmo problema, mas no meu caso eu precisava da versão Swift da resposta acima.
Eu estou trabalhando em um OpenStack Swift Drive para OSX. Quando uma pasta é excluída localmente com o Finder, a exclusão eventualmente se propaga para o servidor, eu precisava de um teste que aguarda a atualização do servidor.
Para evitar a falha da violação da API, mudei minhas expectativas para "weak var" e mudei a chamada para preenchê-la para "zeroFoldersExpectation?.fulfill ()" com o extra "?" como a expectativa agora é opcional e pode se tornar nula, caso em que a chamada de preenchimento é ignorada. Isso corrigiu as falhas.
Em vez de criar expectativa como variável fraca (como sugerido nesta resposta), acho que você também pode definir como variável de bloco e nada no manipulador de conclusão de waitForExpectationsWithTimeout:
Desta forma, você tem certeza de que o ARC não irá lidar com expectativas muito rapidamente.
Assistentes Personalizados no XCTest.
À medida que sua suíte de testes cresce, é importante manter seu código DRY. Ou, não se repita. Você não implementaria o mesmo método três vezes em seu código de produção, então por que fazer isso em seus testes?
Uma maneira fácil de manter a qualidade no seu conjunto de testes é compartilhar asserções entre os testes. Isso pode ser feito extraindo métodos auxiliares para executar asserções comuns.
Por exemplo, no teste da interface do usuário, esperar que os elementos apareçam é bastante detalhado. Não quero escrever isso mais de uma vez se puder evitá-lo.
Vamos analisar um método que aguarda a exibição de um elemento.
Ótimo! Agora podemos apenas chamar waitForElementToAppear (app. cells [& quot; Joe & quot;]) e nosso ajudante cuidará do resto. O que acontece quando o teste falha?
Oh, espere, isso não é bom. Eu quero que a mensagem de falha seja tão próxima da linha de código que eu escrevi quanto possível.
Pense nisso como se você estivesse escrevendo um framework. Você gostaria de forçar seus usuários a pesquisar o código interno da estrutura apenas para ver uma mensagem de erro? Não, claro que não. Vamos mover essa mensagem para mais perto do teste real.
Esta postagem foi atualizada para o Swift 2.2. Para suporte ao Swift 2.1, substitua #file por __FILE__ e #line por __LINE__.
Aqui estamos aproveitando a substituição de falha manual com recordFailureWithDescription (). Isso recebe uma mensagem de falha, referência de arquivo, número de linha e um booleano.
mensagem: a cópia que o usuário verá quando o teste falhar no arquivo: uma referência ao arquivo em que a falha foi originalmente gravada: uma referência ao número da linha em que a falha foi originalmente registrada como esperado: true para falhas de teste e false para não detectado exceções.
O manipulador é chamado o tempo todo e não depende de a afirmação ter falhado ou não. Quando a verificação falha, o parâmetro de erro é preenchido. Por isso, precisamos garantir que ela esteja presente para reprovar nosso teste.
Os parâmetros de arquivo e linha são onde a mágica acontece. Ao especificá-los como opcionais, o chamador não é obrigado a passar nada. E, por padrão, as macros #file e #line podem capturar esses atributos na origem; onde nossos métodos estão sendo chamados. O blog do Swift tem um post incrível sobre como a Apple criou o assert () no Swift.
Muito melhor. Agora podemos adicionar métodos auxiliares ao conteúdo do nosso coração! Podemos continuar passando esses parâmetros pela cadeia e criar uma estrutura de testes altamente abstrata construída no XCTest.
Esperando no XCTest.
Esperar é difícil e esperar no Xcode não é exceção. Até mesmo escolher entre a infinidade de opções oferecidas pelo Xcode e pelo XCTest pode ser difícil. Continue lendo para aprender uma abordagem fácil e direta para esperar por novas classes introduzidas no Xcode 8.3.
Antes do Xcode 8.3.
O Xcode 7 introduziu uma série de novos métodos para ajudar a testar o código assíncrono, a saber, waitForExpectations (timeout: handler :). Este método pode ser usado para, bem, esperar pelas expectativas.
Um XCTestExpectation é uma classe XCTest que avalia continuamente uma expressão até que ela seja atendida ou o tempo limite seja atingido. Eles podem ser usados para esperar que as animações terminem, que elementos apareçam ou até mesmo que os valores-chave sejam alterados via KVO.
Aqui está um breve exemplo da minha postagem de teste de interface do usuário.
Este código é usado em um teste de interface do usuário para esperar que um elemento específico apareça na tela. Você passa no XCUIElement e o ajudante tenta encontrar o elemento por cinco segundos.
O ajudante waitForExpectations é ótimo, mas vem com uma ressalva. Ele gera uma exceção e falha no teste se o tempo limite for atingido. Isso limita sua funcionalidade a casos em que sabemos absolutamente que as expectativas serão atendidas.
O manipulador de conclusão de expectativa.
Tome nota de que passei nil para o parâmetro handler: no exemplo de código.
manipulador: Um bloco XCWaitCompletionHandler opcional para invocar quando todas as expectativas tiverem sido atendidas ou quando o tempo limite de espera for acionado. (O tempo limite é sempre tratado como uma falha de teste.)
E esse manipulador é um alias simples para envolver um erro opcional em um bloco.
Um bloco a ser chamado quando uma chamada para waitForExpectations (timeout: handler: tem todas as expectativas atendidas ou tempo limite esgotado).
typealias XCWaitCompletionHandler = (Erro?) - & gt; Vazio.
À primeira vista, essa definição é empolgante, é fácil inferir que o erro conterá todo tipo de informação útil. No entanto, na prática, não é esse o caso. Muito raramente foi algo mais do que um erro genérico sem descrição (localizada). рџ˜ћ.
Para nossa sorte, o Xcode 8.3 adicionou algumas novas classes e ajudantes para tornar a compreensão do motivo da falha um pouco mais fácil de entender.
O restante deste post faz referência à nova funcionalidade introduzida no Xcode 8.3 Beta.
Digite XCTestWaiter.
Gerencia a espera - pausando o contexto de execução atual - para uma matriz XCTestExpectations. Os garçons podem ser usados com ou sem um representante para responder a eventos como conclusão, tempo limite ou cumprimento de expectativa inválido. O XCTestCase está em conformidade com o protocolo delegado e relatará automaticamente os tempos limite e outros eventos inesperados como falhas de teste.
Os garçons podem ser usados sem um representante ou qualquer associação com uma instância de caso de teste. Isso permite que bibliotecas de suporte de teste forneçam métodos convenientes para aguardar sem precisar passar casos de teste por meio dessas APIs.
À primeira vista, o XCTestWaiter é simplesmente uma nova abordagem para esperar que o XCTestExpectation seja cumprido. No entanto, existem algumas gemas escondidas abaixo da superfície.
Primeiro, vamos converter a tag "old" amostra para usar a nova classe.
wait (for: timeout :) retorna um XCTestWaiterResult, um enum representando o resultado do teste. Pode ser um dos quatro valores possíveis: concluído, timedOut, incorrectOrder ou invertedFulfillment. Somente o primeiro, concluído, indica que o elemento foi encontrado com sucesso dentro do tempo limite alocado.
Uma grande vantagem dessa abordagem é que o conjunto de testes é lido como um fluxo síncrono. Não há bloco de retorno de chamada ou manipulador de conclusão. O método auxiliar simplesmente retorna um booleano, indicando se o elemento apareceu ou não.
Expectativas não cumpridas não falhar automaticamente…
Na minha opinião, esta é a maior melhoria para o quadro. Você está agora completamente no controle de quando e como falhar em seus testes se uma expectativa não for cumprida. Isso permite esperar por elementos opcionais, como uma tela de login ou uma caixa de diálogo de autorização de serviços de localização.
Você também pode dividir cada tipo de XCTestWaiterResult e reprová-los com mensagens de erro individuais. Por exemplo,.timedOut pode mencionar quanto tempo o tempo limite estava incorreto, enquanto o ORDER pode usar as Expectativas realizadas para anotar quais foram bem-sucedidas e quais ainda estamos aguardando.
Múltiplas Expectativas
Mais de um XCTestExpectation pode ser passado para o garçom, que pode ser usado em dois cenários diferentes.
Quaisquer das expectativas precisam ser atendidas - assim que um é atendido, o garçom para de esperar. Todas as expectativas precisam ser atendidas - o garçom continua a esperar até que todas estejam preenchidas.
Para indicar que todas as expectativas importam, simplesmente chame wait (for: timeout: enforceOrder :). O último parâmetro indicará ao framework se a ordem de atendimento também é importante.
Novas subclasses de XCTestExpectation.
Juntamente com a nova classe de garçons, o XCTestExpectations foi subclassificado para tornar as expectativas específicas um pouco mais fáceis de serem escritas. Sugiro usá-las sempre que possível, a legibilidade ajuda muito a escrever um conjunto de testes de manutenção.
XCTPredicateExpectation.
XCTKVOExpectation.
XCTNSNotificationExpectation.
Eu não consigo fazer isso funcionar. Se alguém tiver sucesso com esta subclasse, por favor me avise nos comentários.
Obrigado pela ajuda, Brian!
Xcode 8.4 e Beyond.
É reconfortante ver a Apple reinvestindo em sua estrutura de testes; não há muita atividade no XCTest desde sua renovação no Xcode 7. Estou ansioso para experimentar algo novo que venha com o próximo lançamento!
wait For Expectations With Timeout: manipulador:
Aguarda até que todas as expectativas sejam atendidas ou o tempo limite seja atingido.
Declaração.
Parâmetros
A quantidade de tempo em que todas as expectativas devem ser atendidas.
Um bloco opcional do Manipulador de Conclusão do XCWait para invocar quando todas as expectativas tiverem sido atendidas ou quando o tempo limite de espera for acionado. (O tempo limite é sempre tratado como uma falha de teste.)
Discussão.
Este método cria um ponto de sincronização no fluxo de um teste. Apenas uma espera Por Expectativas Com Tempo Limite: manipulador: pode estar ativo a qualquer momento, mas várias sequências discretas de "criam expectativas e esperam que elas sejam atendidas". podem ser encadeados juntos.
Este método aguarda as expectativas criadas apenas com os métodos de conveniência do XCTest Case. Esse método não espera as expectativas criadas manualmente por meio de inicializadores no XCTest Expectation ou em suas subclasses.
Para aguardar expectativas criadas manualmente, use a opção esperar por expectativas: tempo limite: ou espere por expectativas: tempo limite: impor ordem: métodos ou os métodos correspondentes no XCTWaiter, passando uma lista explícita de expectativas.
Os clientes não devem manipular o loop de execução enquanto usam esta API.
Комментарии
Отправить комментарий