Thursday 22 March 2018

Aguarde as expectativas com o tempo limite do exemplo


Cheat Sheet e exemplos de teste de interface do usuário.
Atualização 10/20/16: esta postagem e o código de exemplo no GitHub foram atualizados para o Swift 3.0.
Pouco depois da Apple, "Hey Siri" evento o Xcode 7 GM foi lançado para desenvolvedores. Vamos colocar os betas atrás de nós e dar uma olhada em alguns exemplos reais de teste de interface do usuário.
Todos os exemplos usam um host de teste que ajuda você a gerenciar sua equipe de vôlei. O aplicativo, Volley, permite ao usuário gerenciar a lista de equipe, ajustar a formação e ver os resultados do jogo. Sinta-se à vontade para dar uma olhada no código-fonte antes de continuar para se familiarizar com o funcionamento dele.
Por que não usar gravação?
Você certamente pode usar o recurso de gravação do teste de interface do usuário por conta própria. A gravação faz sentido ao adicionar testes de regressão a uma base de código existente. Mas você perderá as vantagens de escrever seus próprios testes. No entanto, existem três razões pelas quais a gravação não é sempre a melhor ideia.
Com o desenvolvimento orientado a testes, você primeiro escreve seus testes, para que você não tenha um aplicativo para gravar! A gravação não funciona sempre. Gravar a interação com alguns elementos, como visualizações da Web, nunca funciona, e a manipulação do UISlider é, na melhor das hipóteses, complicada. A razão mais importante para aprender manualmente o teste da interface do usuário é aprender, você mesmo! Em algum momento você precisará ler o código gerado pelo Xcode e depurá-lo. Se você não consegue descobrir o que está acontecendo, vai ter dificuldade em decifrar onde algo deu errado. Além disso, se você estiver usando algum controle personalizado, precisará escrever os testes.
Funcionalidade Básica.
Esses trechos de código pressupõem que você esteja familiarizado com os conceitos básicos do teste de interface do usuário. Se você está apenas começando, ou gostaria de uma atualização, sugiro ler uma visão geral do teste de interface do usuário no Xcode 7.
Os exemplos também assumem que seu aplicativo foi lançado e você tem uma referência a ele, app. Você pode fazer isso na sua aula de teste & # 39; O método setUp () garante que o aplicativo seja iniciado para todos os testes.
Como afirmar um elemento existe.
Vamos começar de forma simples. A primeira coisa que você fará ao validar seu aplicativo com o teste de interface do usuário é declarar se existe um elemento. Isso é feito facilmente consultando um elemento e perguntando se ele existe.
Usando a tela inicial do Volley, podemos afirmar que o nome do aplicativo existe assim. Observe o envolvimento da chamada em uma afirmação do XCTest. Isso garante que o teste falhará se o rótulo não existir.
Como esperar que um elemento apareça.
Ver a nossa agenda no Volley mostra-nos o nosso último par de resultados do jogo. Tudo bem, 2-1! Não é um mau começo para a temporada. Mas quando é o nosso próximo jogo?
Tocar no botão Carregar mais jogos simula a busca de dados de um servidor. Depois de dois segundos, nosso quarto jogo volta.
Aqui, criamos uma consulta para aguardar um marcador com o texto & quot; Jogo 4 - Amanhã & quot; aparecer. O predicado corresponde quando o elemento existe (element. exists == true).
Em seguida, passamos o predicado e o avaliamos no rótulo. Finalmente, iniciamos o jogo de espera com waitForExpectationsWithTimeout: handler:. Se cinco segundos se passarem antes que a expectativa seja atingida, o teste falhará.
Como imprimir a hierarquia de acessibilidade.
Imprimir a hierarquia de acessibilidade é uma boa maneira de "ver o que a estrutura vê". Você pode usar isso e o Inspetor de Acessibilidade para depurar a consulta e selecionar elementos.
Interagindo com os controles do sistema.
Além de validar e verificar condições básicas, convém interagir com seu aplicativo. O XCUIElement expõe algumas funções cruciais para nos ajudar a explorar a interface. Esse método usa um XCUIElementQuery para localizar o elemento por seu rótulo ou identificador de acessibilidade.
Como tocar um botão.
Como digitar texto em um campo de texto.
Digitar em um campo de texto requer que o alvo tenha foco. Basta tocar nele para garantir que o campo de texto seja o primeiro respondedor.
Como descartar um alerta.
Primeiro, encontre o alerta consultando seu título. Você pode então referenciar seus botões encadeando o seletor e tocando em qual deles você deseja.
Você pode tentar isso em Vôlei, indo para a tela de programação e tocando no & quot; Finish Game & quot; botão.
Como interagir com um alerta do sistema.
Ah, alertas do sistema, a maldição de todos os testadores do iOS & # 39; existência. Quase todas as outras estruturas com as quais trabalhei tiveram problemas com alertas do sistema, sejam serviços de localização, notificações por push ou acesso a suas fotos.
Com o Xcode 7.1, o teste de interface do usuário pode finalmente interagir de forma confiável com essas caixas de diálogo incômodas. Existem, no entanto, duas pequenas dicas.
Em primeiro lugar, configure um & quot; Manipulador de interupções da interface do usuário & quot; antes de apresentar o alerta. Esta é a nossa maneira de dizer ao framework como lidar com um alerta quando ele aparecer.
Em segundo lugar, depois de apresentar o alerta, você deve interagir com a interface. Basta tocar no aplicativo funciona bem, mas é necessário.
Como deslizar um controle deslizante.
Ao ajustar um UISlider com teste de interface do usuário, você não passa o valor que deseja definir. Em vez disso, você normaliza o valor em uma escala de 0 a 1. Por exemplo, o controle deslizante no Volley tem um intervalo de 0 a 10. Para deslizar o controle deslizante para 7, passamos em 0,7, ou, como eu gosto de pensar nisso, 70%.
Como selecionar um item de um selecionador.
XCUIElement tem um método especial para interagir com o UIPickerView s. Para um selecionador com apenas uma roda, podemos acessá-lo via element () e depois ajustar ao nosso valor especificado.
Picker com uma roda.
Seletor com várias rodas.
Se o selecionador é mais complexo com várias rodas, temos um pouco para fazer. Precisamos de uma maneira de identificar as diferentes rodas para o framework. Em conformidade com o UIPickerViewAccessibilityDelegate fornece a interface certa para definir o texto de acessibilidade em cada selecionador.
Isto, então, define o título de acessibilidade da primeira roda como "Atacadores de Formação, 4 atacantes". Observe como o valor selecionado entra? Para realmente selecionar o elemento, precisamos combiná-lo com um predicado BEGINSWITH.
Como tocar em links em uma visualização da Web.
Não há nada muito emocionante acontecendo aqui, o que leva a uma API limpa. O método tap () pode ser usado com o UIWebView e o WKWebView.
Interações complexas.
Como afirmar uma visão está na tela.
Um comportamento estranho de exists () é que ele retorna verdadeiro mesmo que o elemento esteja fora da tela. Você tem que pular alguns aros para ter certeza de que o elemento está realmente visível para o usuário.
Podemos testar isso afirmando que o quadro do elemento está contido no quadro da janela com CGRectContainsRect ().
Como reordenar células de tabela.
Abra o Inspetor de Acessibilidade e passe o mouse sobre a tela Gerenciar Lista. Os pequenos ícones de reordenação obtêm automaticamente seus próprios títulos de acessibilidade com base na célula em que estão contidos. Aqui, o rótulo da célula é & quot; Adrienne & quot; então, o identificador do ícone se torna "Reordenar Adrienne".
Agora podemos usá-los para arrastar as células para cima e para baixo.
Como & quot; Puxar para atualizar & quot;
Para replicar esse gesto, precisamos incluir a API XCUICoordinate. Você pode usar esses objetos para interagir com pontos específicos na tela, não necessariamente vinculados a qualquer elemento em particular. Isso se torna muito útil quando queremos arrastar um elemento para um local específico.
Primeiro, pegue uma referência à primeira célula da sua tabela. Em seguida, crie uma coordenada com deslocamento zero, CGVectorMake (0, 0). Isso normalizará um ponto logo acima da primeira célula.
Usando este ponto, podemos criar uma coordenada imaginária mais abaixo na tela. Descobri que um dy de seis é o menor valor necessário para acionar o gesto de puxar para atualizar.
Podemos então executar o gesto, pegando a primeira coordenada e arrastando-a para a segunda.
Procurando por uma técnica específica ou perceber que algo está faltando? Deixe um comentário abaixo ou entre em contato comigo no Twitter. Estou mais do que feliz em adicioná-lo ao post!

Waitforexpectationswithtimeout example
Ao escrever um determinado teste assíncrono usando XCTest e XCTestExpectation, gostaria de afirmar que um determinado bloco não foi executado. O código a seguir é bem-sucedido ao afirmar que um bloco foi executado e, se não, o teste falhará.
Não parece haver uma maneira óbvia de executar isso ao contrário; onde o teste é bem-sucedido se o bloco não for executado após o tempo limite e falhar se for executado antes do tempo limite. Além disso, gostaria de afirmar que o bloco foi executado mais tarde quando uma condição diferente é atendida.
Existe uma maneira simples de fazer isso com o XCTestExpectation ou terei que criar uma solução alternativa?

Teste de unidade do iOS.
É sobre TDD, testes unitários e criação de código livre de bugs no iOS.
Testes de unidade assíncrona usando o XCTestExpectation.
Me deparei com um post interessante de Phil Beauvoir sobre Teste de Unidade Assíncrona no Xcode 6 usando o novo XCTestExpectation. Ele explica como ele converteu os testes de unidade assíncronos do Objective-C existentes para o Swift, ao mesmo tempo tornando-os mais eficientes e legíveis usando uma instância do XCTestExpectation e waitForExpectationsWithTimeout ().
O XCTestExpectation é uma classe simples com 1 método: fulfill (). Crie uma instância dele e chame fulfill () quando a expectativa for atingida.
Em sua seção de declaração de teste, chame waitForExpectationsWithTimeout (), passando pelo XCTestExpectation, e Voila! Testes unitários assíncronos.
Ao contrário de usar um loop de rotação, isso informa explicitamente ao framework XCTest que o seu teste está esperando por um evento assíncrono, permitindo que ele realize outros testes enquanto espera.
Pós-navegação.
Um pensamento sobre & ldquo; Testes de unidade assíncrona usando XCTestExpectation & rdquo;
Eu comecei a usar as expectativas um pouco. Eles são realmente bons porque me permitem remover algumas classes de suporte de teste cheias de funcionalidades semelhantes para lidar com código assíncrono. Definitivamente vale o esforço para aplicar.

Como usar as expectativas do iOS para testar funções assíncronas sem um método de retorno de chamada.
A estrutura de testes da Apple deu grandes passos nos últimos anos. Ela se tornou madura até o ponto em que o desenvolvimento orientado a testes (TDD) não é apenas viável, mas agradável. A introdução de expectativas resolveu um dos maiores obstáculos no teste: operações assíncronas. Acompanhe enquanto falamos sobre o caso de uso comum para métodos assíncronos com blocos de conclusão (também conhecidos como XCTestExpectation). Também veremos como podemos usar o XCTestExpectation para testar processos assíncronos que não possuem um método de retorno de chamada.
Como as expectativas melhoram o TDD.
Antes das expectativas, testar qualquer código que tivesse um componente assíncrono exigia uma webwork de código que, por si só, provavelmente precisava de testes, ou mais, do uso de uma biblioteca de testes de terceiros (por exemplo, Kiwi, specta). Embora as expectativas estivessem atrasadas para a festa, aqueles desenvolvedores geniais da Apple os adicionaram de uma forma graciosa e intuitiva que os fez parecer como se tivessem feito parte da família de testes por gerações.
Quão gracioso? Vamos pegar este trecho por exemplo:
O resultado acima será pior do que a falha do teste, pois o método de teste será encerrado, mesmo que haja um manipulador de conclusão com uma afirmação informando que o teste foi aprovado e tudo está correto. Usando as expectativas, no entanto, apenas adicionamos algumas linhas de código:
Com a expectativa definida na primeira linha, podemos executar nosso método com segurança. Quando recebemos nossa resposta no manipulador de conclusão, nossa afirmação é testada e chamamos cumprimento na expectativa. Até que fulfill seja chamado, o método de teste é considerado concluído, portanto, nosso método tem bastante tempo para iniciar sua consulta e retornar uma matriz. Então nós batemos nossa afirmação e chamamos cumprir se a afirmação é verdadeira ou não.
E se a consulta parar aí? Não é isso.
Um teste com falha? Vai segurar o resto dos testes?
Bem, isso é o que nosso último pequeno código faz. waitForExpectationsWithTimeOut: handler: faz exatamente como é excessivamente detalhado, mas no nome do nariz implica. Passe um duplo e espere muitos segundos para que a expectativa seja satisfeita. Se esse tempo (neste caso, cinco segundos) passar, você receberá uma mensagem de falha informando que a expectativa expirou.
Aplicações modernas tornaram-se dependentes de rede, bestas de UI rápidas, o que significa que muito do trabalho pesado é feito de forma assíncrona - ou esperando por uma resposta de rede, ou empurrado para um thread de segundo plano. As expectativas oferecem uma maneira intuitiva de testar esses métodos, ao mesmo tempo que você tem menos uma razão para evitar a criação de testes em seus aplicativos.
Como testar funções assíncronas sem um método de retorno de chamada.
E se eu não trouxesse um manipulador de conclusão para essa festa de teste? Expectativas funcionam perfeitamente para funções assíncronas que possuem um manipulador de conclusão de algum tipo. Esse não é o caso das funções assíncronas que não têm blocos. Como podemos testá-los sem recorrer à adição de um bloco apenas para fins de teste?
Poderíamos, é claro, voltar para o DDBE (Luminosos Dias Antes das Expectativas) e alavancar semáforos ou grupos de despacho para resolver isso. Mas então estaríamos nos afastando da "Alegria do TDD" para os testes excessivamente complexos que tentamos evitar desde o começo. Bem, não tenha medo! Coloque o Grand Central Dispatch de volta à sua caverna e sente-se novamente ao redor do calor das expectativas!
Digamos que tenhamos uma classe de fonte de dados para nossa visualização de tabela cujo init inicie um método que consulte nosso banco de dados remoto e preencha uma matriz com os resultados. Queremos testar isso. Depois de chamar o init, a matriz do objeto resultante é preenchida, mas não queremos testá-la logo depois de chamar o init. Assim:
Combinando uma expectativa com dispatch_after, você tem uma maneira de aplicar testes a um método ou propriedade que depende de operações assíncronas privadas sem precisar expor métodos ou manipular um manipulador de conclusão apenas para fins de teste.
Nota conclusiva.
A equipe da Apple fez um ótimo trabalho ao tornar as expectativas uma maneira intuitiva de testar operações assíncronas. Integrá-los em seu processo de teste é indolor, enquanto aqueles que estão apenas começando com o teste provavelmente assumirão que o XCTestExpectation está presente desde o primeiro dia.
Junte-se a mais de 20.000 outros leitores.
Inscreva-se para ser notificado sobre novas postagens no blog e seja o primeiro a receber guloseimas de aplicativos úteis do Savvy Apps!
Jaz é um desenvolvedor de aplicativos que gosta de criar interações de bom gosto, frotas de bots dominadores do mundo e. trocadilhos.
Artigos recomendados.
Custos de desenvolvimento de aplicativos: o que separa um aplicativo de US $ 10.000 de um aplicativo de US $ 100.000?
Ainda há confusão no mercado sobre por que o custo para desenvolver um aplicativo pode variar muito de uma empresa para outra. Enquanto Savvy.
7 perguntas que os startups precisam responder antes de criar um aplicativo.
Nos sete anos em que a Savvy Apps criou aplicativos premiados, trabalhamos amplamente com startups e empreendimentos em estágio inicial. Se foi um empreendedor quem.
28 métricas que importam para o seu aplicativo.
Você gastou tempo e dinheiro construindo seu aplicativo, agora você precisa começar a avaliar como está indo. Divulgamos 28 das métricas mais úteis em.
Quanto tempo leva para fazer um aplicativo?
Embora isso varie muito, a resposta geral que fornecemos às pessoas que nos perguntam quanto tempo leva para criar um aplicativo é de quatro a seis meses. Que.

Teste assíncrono com o Xcode 6.
Em 2013, a Apple enviou uma estrutura de testes renovada no Xcode chamada XCTest, e houve muita alegria. A estrutura antiga não era atualizada há anos e várias ferramentas de teste e estruturas de terceiros surgiram para fornecer novos recursos e capacidades. Foi bom ver as ferramentas embutidas ganharem algum amor novamente, e este ano, a Apple está enviando alguns recursos com o Xcode 6 que estavam faltando na atualização do ano passado. Um que fico particularmente feliz em ver é o suporte para testes assíncronos.
Se tivermos um teste que tenha que iniciar uma tarefa assíncrona, seja em outro thread ou no runloop do thread principal, como vamos testá-lo?
Considere uma solicitação da web. Poderíamos lançar uma solicitação da web e passar um bloco de conclusão e fazer nossas asserções de teste no manipulador de conclusão ou não. No entanto, como a solicitação da Web ainda não foi feita, muito menos uma resposta recebida nem nosso bloco de conclusão foi chamado, nosso método de teste será encerrado antes que as asserções sejam testadas.
Vamos olhar para um teste para uma classe que baixa páginas da web. Normalmente, não queremos fazer solicitações reais da web nos testes. Em vez disso, apagamos as solicitações usando alguma ferramenta (eu sou parcial para OHHTTPStubs). Mas, para os propósitos desses exemplos, quebraremos algumas regras e faremos solicitações reais da web.
Podemos dar à classe em teste um bloco de manipulador de URL e conclusão, e ela fará o download da página e chamará o bloco, passando uma string contendo a página da web ou uma string vazia se ocorrer uma falha. Não é uma ótima API, mas, novamente, estamos quebrando algumas regras. No entanto, o código de teste abaixo nunca irá falhar. O método de teste retornará sem dar ao bloco completionHandler a chance de ser chamado.
Antes da versão do XCTest do Xcode 6, usando apenas o que vem no estanho com o Xcode, poderíamos sentar e girar em um loop while que chama o loop de execução da thread principal até que a resposta chegue ou algum período de timeout tenha decorrido. Aqui está o código de teste de trabalho, do jeito antigo.
O loop while executa o loop de execução do thread principal por 10 milissegundos de cada vez até que a resposta chegue, ou até que 5 segundos decorram sem que ele tenha chegado. Isso é reparável. Não é terrível. Não é o fim do mundo do desenvolvimento de software - mas não é ótimo.
Agora há um caminho melhor.
Altas expectativas.
Com o Xcode 6, a Apple adicionou expectativas de teste ao framework XCTest na forma da classe XCTestExpectation. Quando instanciamos uma expectativa de teste, a estrutura de teste espera que ela seja atendida em algum momento no futuro. Nosso código de teste preenche a expectativa no bloco de conclusão com uma chamada para o preenchimento do método XCTestExpectation. Isso substitui a configuração de uma flag como responseHasArrived no exemplo anterior. Em seguida, informamos à estrutura de teste que espere (com um tempo limite) que suas expectativas sejam atendidas pelo método XCTestCase waitForExpectationsWithTimeout: handler:. Se o manipulador de conclusão for executado dentro do tempo limite e o atendimento de chamadas, todas as expectativas do teste serão atendidas. Caso contrário, o teste terá uma existência triste, solitária e não cumprida, até que saia do escopo. E por viver uma existência triste, solitária, não cumprida, quero dizer que a expectativa não passa no teste após o tempo limite.
A expectativa fracassada não deve ser tão desanimada. Lembre-se de que um resultado insatisfatório não é sinal de um teste ruim; um resultado indeterminado é. Essa expectativa pode sentir orgulho ao declarar o fracasso.
Aqui está um exemplo usando o XCTestExpectation:
Crie a expectativa com uma descrição para tornar os resultados mais legíveis. No bloco de conclusão, chame [expectativa de cumprimento] para dizer ao teste que essa expectativa foi, de fato, cumprida. Em seguida, saia no waitForExpectationsWithTimeout: manipulador: até que a solicitação seja enviada, a resposta chegue e nosso manipulador de conclusão seja chamado ou o tempo limite ocorra.
Isso é bom para o Objective-C, mas também podemos fazê-lo na nova linguagem Swift da Apple.
E isso é tudo. É uma classe fácil de usar para testar código assíncrono.
Não é possível obter informações suficientes sobre o iOS 8 e o Swift? Junte-se a nós para o nosso iOS inicial com bootcamps Swift e Advanced iOS.

Gotchas XCTestExpectation.
O XCTestExpectation simplifica o teste de código no estilo de retorno de chamada, mas algumas de suas escolhas de design tornam os testes mais frágeis, a menos que sejam mitigados:
Ele explode se tudo funcionar direito, mas depois do que você esperava. Explode se tudo der certo mais de uma vez.
Este artigo apresenta duas mitigações concretas:
Use referências fracas para garantir que a expectativa morra antes que possa causar problemas. Use uma API de promessas diferente para fazer sua espera.
Uma revisão rápida.
O XCTestExpectation é a ferramenta que a XCTest fornece para lidar com APIs assíncronas.
É uma promessa / futuro com um propósito: para responder a pergunta, "ela foi preenchida no tempo?"
Para usá-lo, peça ao caso de teste para criar um ou mais:
aguarde uma quantidade configurável de tempo para cada expectativa pendente ser preenchida:
e registrar uma falha de teste se o tempo acabar antes que isso aconteça:
Espera assíncrona falhou: Excedido o tempo limite de 1 segundo, com expectativas não atendidas: "Acontecerá, confie em mim".
Teria sido bem sucedido se tivesse sido preenchido a tempo:
Exemplo: nós ligaremos para você.
Você não pode usar o framework XCTest de um Playground (rdar: // problem / 17839045), então você precisará lançá-lo em um projeto completo:
Vá em frente e corra isso. Tudo funciona bem - por enquanto:
O conjunto de testes é iniciado, tudo é executado, o teste falha devido a um tempo limite enquanto aguarda a expectativa a ser atendida e o processo é encerrado. É assim que o XCTestExpectation deve funcionar.
Kaboom: Perdendo a janela.
Nós só fizemos o único teste, no entanto. Digamos que você tenha mais testes para executar depois desse.
Podemos falsificar isso adicionando um novo método de teste cujo nome é classificado em ordem alfabética após nosso teste testNotWaitingLongEnough que executa o runloop um pouco antes de sair.
Convenientemente, o XCTest executa testes em ordem alfabética, de modo que o executor de testes execute o primeiro teste, execute este segundo e saia.
Aqui está o nosso novo método de teste:
E agora estamos sentados no depurador. Oof, que smarts.
Dê uma olhada no que está acontecendo nesse backtrace:
Nosso teste do Zzz está pendurado na execução do runloop. O after (seconds: call :) termina de esperar e chama seu callback. O retorno de chamada preenche uma expectativa que pertence ao primeiro teste (já concluído, que já falhou). Isso tropeça em um erro "você está segurando errado" & rdquo; afirmação no quadro de teste:
Aplicativo de finalização devido a uma exceção não detectada & nbsp; NSInternalInconsistencyException & rsquo ;, motivo: & lsquo; violação da API - chamada - [XCTestExpectation fulfill] após o término do contexto de espera para chamadas de volta. & Rsquo;
Você pode se deparar com isso na prática ao escrever testes de integração em um serviço de back-end ativo, mas nem sempre rápido para responder.
Kaboom: Chamando duas vezes.
Essa não é a única maneira de as coisas darem errado.
O que acontece se o nosso retorno de chamada tiver um comportamento pelo menos uma vez, e não exatamente uma vez, e ligar novamente duas vezes?
Nós tropeçamos mais uma afirmação no XCTest:
Aplicativo de finalização devido à exceção não detectada & nbsp; NSInternalInconsistencyException & rsquo ;, motivo: & lsquo; violação da API - várias chamadas feitas para - [XCTestExpectation fulfill] para chamadas de volta. & Rsquo;
Isso provavelmente indica um erro real no código que está chamando o retorno de chamada a maior parte do tempo, mas se isso não acontecer, você também precisará saber e ser capaz de evitar essa afirmação.
O que é errado?
Este cenário de retorno de chamada dupla chama duas vezes em sucessão. Mas, se houvesse um atraso entre a primeira e a segunda chamada, e o corredor de teste tivesse saído durante esse atraso, você teria um teste bem-sucedido, em vez de travar todas as vezes.
Com um atraso entre os retornos de chamada, você só desarmará a declaração quando outros testes mantiverem o processo do executor de teste em execução por tempo suficiente.
Essa situação é semelhante à do callback muito atrasado: nenhum problema aparece até que alguma outra coisa acabe.
Você nunca os derrotará quando estiver fazendo o teste mais recente, porque um executor de testes executando apenas o teste assíncrono sairá assim que o tempo de espera acabar, antes do atraso / segundo retorno de chamada pode ocorrer. Você pode nem mesmo derrubá-los quando você executar o conjunto de testes inteiro no início, porque eles podem ser o último teste na corrida ou os testes que seguem não são executados por tempo suficiente.
Isso também é desagradável de se deparar: quando uma afirmação é acionada, ela bombeia todo o processo de teste. (Desembrulhar um opcional implicitamente não desembrulhado para encontrar um nulo tem o mesmo efeito.)
Essas afirmações não são falhas de teste que permitiriam que os testes continuassem; em vez disso, o XCTest trata como erro do programador:
Cumprindo uma promessa depois que seu teste já terminou Enchendo uma promessa já preenchida.
Para ser justo, esses casos são chamados na documentação do XCTestExpectation. fulfill ():
Chame para preencher uma expectativa como tendo sido cumprida. É um erro ligar para uma expectativa que já foi atendida ou quando o caso de teste que preencheu a expectativa já foi concluído.
mas a documentação não é explícita que "é um erro" traduz para "e vai bombardear todo o seu processo de teste".
Evitando estas asserções.
Em ambos os casos, o problema é que estamos chamando o cumprimento quando não deveríamos. Portanto, não façamos isso.
Deixe a expectativa morrer com o teste.
O XCTest, na verdade, se apega às expectativas que cria para poder coletá-las durante a chamada de espera.
Nosso método de teste ainda não precisa de outra referência forte à expectativa; Se, em vez disso, trabalharmos com uma referência fraca em nosso fechamento de callback, a expectativa morrerá com o nosso teste, em vez de demorarmos a tropeçar após o término do teste, e teremos transformado nosso retorno de chamada em um não operacional.
Primeiro, neutralize o teste bombardeado pelo tempoNotWaitingLongEnough prefixando seu nome com um x para que ele não seja mais usado pelo test runner:
Agora clone, mas desta vez, use uma referência fraca à expectativa:
Execute a suíte LateCallback novamente, e os logs agora parecem (ou pule para o resumo):
Nosso testZzz é executado até a conclusão e passa, e o processo de teste sai em seus próprios termos relatando uma falha.
O retorno de chamada atrasado ainda acontecia, mas, àquela época, promiseToCallBack tinha sido zerado, então nunca chamamos fulfill ().
Mate a expectativa de forma proativa.
E quanto ao caso de callback duplo? Podemos usar o mesmo truque, só que desta vez, vamos aniquilar proativamente a expectativa:
Com o teste inseguro neutralizado por meio do truque de prefixo, executar a classe de teste fornece (ou pule para o resumo):
Como explicitamente definimos a promessa como nula, acabamos cumprindo uma vez. Nenhum dano, não falta.
Use uma API de promessa diferente.
Se você já tem uma API escrita em termos de uma promessa / futura biblioteca, como Deferred, então não há necessidade de usar as promessas do XCTest:
Sempre atribua suas expectativas a uma referência fraca e, em seguida, liberte seu retorno de chamada caso seja inexato. Nos raros casos em que você espera que seu callback seja acionado mais de uma vez, você pode evitar o cumprimento aniquilando sua referência fraca depois de preenchê-la e, em seguida, ignorando futuras chamadas. Mais provavelmente, você sabe quantas vezes você deve ser chamado, e você quer cumprir a promessa somente na última chamada. Mas a solução alternativa está lá, se você precisar. Se você já estiver trabalhando com uma API baseada em promessa, poderá ignorar o XCTestExpectation e usar qualquer API de espera e visualização fornecida por essa promessa, em vez da API do XCTest. Isso tem a vantagem adicional de linearizar seu código de teste, eliminando a necessidade de manipular o valor entregue no fechamento (ou manualmente, transferi-lo para fazer uma confirmação após a conclusão da espera do XCTest).
Direitos autorais & # 169; 2018 Jeremy W. Sherman. Todos os direitos reservados.

No comments:

Post a Comment