Aqui estão as funções assíncronas Im testing no Xcode usando XCTestExpectation. Para testar o código, criei 3 expectativas para aguardar que cada uma das chamadas assíncronas seja concluída. Quando espero que as expectativas sejam cumpridas usando o padrão, mas isso resulta em um SIGABRT com o seguinte erro Falha de asserção em - XCTestExpectation cumprir, /Library/Caches/com. apple. xbs/Sources/XCTestSim/XCTest-9530/XCTestFramework/Classes /XCTestCaseAsynchronousTesting. m:450 Ive testado com êxito a função usando dispatchgroups e que funciona. Mas não poderia descobrir por que a XCTestExpectation está levantando uma exceção para várias expectativas. Perguntou Jan 4 às 9: 25Swift tem um problema especial para mostrar o ponto de ruptura de exceção correto quando fechamentos estão presentes no mesmo escopo. Eu vi o mesmo problema em um XCTestCase que usou dispatchafter e até mesmo através do ponto de interrupção de exceção era a mesma linha como waitForExpectationsWithTimeout o caso de teste estava falhando por causa de um downcast em um objeto nil. Eu sei que este não é o seu caso, mas sempre que isso acontece eu sugiro remover as declarações de uma linha de cada vez e executando o teste após cada remoção. Se o teste não falhar, você identificou o culpado. Esta é, infelizmente, a melhor opção no momento desta escrita sempre que Swift mostra um ponto de interrupção de exceção em uma linha que não faz sentido, especialmente a infame linha 0 de uma classe que você pode ver em ferramentas de relatório de falhas. Deixe-nos saber se você descobriu o seu crash. I estou trabalhando em um projeto iOS e Im encarregado de testar a maior parte dela. Como eu escrever alguns testes, muitas vezes tenho a necessidade de esperar por um método assíncrono para concluir e, em seguida, testar que algo não aconteceu. Por exemplo . Tente fazer o login com um nome de usuário inválido e senha, aguarde até que as comunicações de rede são concluídas e, em seguida, teste que o usuário não foi capaz de login Swift tem alguns métodos bacana para testar esses tipos de coisas que eu uso mais são expectationForPredicate e waitForExpectationsWithTimeout. Esses métodos são bons para testar que algo aconteceu após o método assíncrono terminar. No entanto, para testar que algo não aconteceu (que é o que eu quero), não há parece ser nada projetado especificamente para isso. Eu não posso usar predicados porque isso fará com que o teste de tempo limite cedo Eu não posso modificar o código que está sendo testado, porque é um retorno de chamada de lifecycle app e nós testadores geralmente não modificam qualquer código, nós apenas testar Qual é por isso que eu projetei este método O principal A função faz é agendar um temporizador e cumprir todas as expectativas antes de o método waitForExpectationsWithTimeout expirar. Esta é a melhor maneira de lidar com esta situação O que posso melhorar com este método (além de comentar) Quaisquer problemas de concorrência que eu deveria estar preocupado Para adicionar algum contexto, waitForExpectationsWithTimeout fará com que o teste falhe se não as expectativas são cumpridas antes Que timesout, que é por isso que eu tinha para cumprir todas as expectativas apenas antes desta timeout ocorre Perguntado 23 de março às 21:03 Esta é uma solução extremamente complicada para um problema relativamente simples. O método waitForExpectationsWithTimeout deve efetivamente ser usado garantir que uma expectativa assíncrona particular foi cumprida. Assim, no caso em que estamos testando se o usuário foi ou não logado com êxito, itd ser tentador para escrever algo ao longo das linhas de: Mas problemático, este teste pode falhar por duas razões: O usuário não foi bem-sucedido. Não foi cumprida no prazo. Se o teste falhar, não podemos ter certeza se ele teria passado dado um limite de tempo mais longo ou se ele retornou muito rapidamente, mas não foi bem sucedido. Então, precisamos modificar nosso teste para parecer mais com isto: Agora, o teste determina se o código assíncrono será executado ou não, e se assim for, verificamos se o login foi ou não um sucesso (ou o que a variável de sucesso representa aqui) . Agora, você está procurando o caso oposto. Você não quer saber se o usuário efetuou login ou não, mas se o usuário não foi impedido de fazer logon. E isso é tão simples como inverter um XCTAssertTrue para um XCTAssertFalse. Importante, este teste padrão não requer nenhum código complicado (que nós teríamos que naturalmente escrever testes em torno de nos). Nossos testes estão usando coisas puramente fora da caixa Xcode teste suite - exatamente o que qualquer um olhando para a nossa base de código seria de esperar para ver. É muito simples o que está acontecendo aqui. E nós somos capazes de distinguir entre se a chamada assíncrona nunca aconteceu ou se aconteceu, mas temos um mau resultado. Theres uma enorme diferença aqui entre um teste falha porque o código assíncrono didnt executar antes do nosso tempo fora e ele fez correr, mas deu um resultado incorreto. Precisamos distinguir claramente entre esses resultados, e fazê-lo não exige escrever qualquer código complicado qualquer. Uma nota importante aqui, certifique-se de que cumprindo a expectativa é a última coisa que você faz nos retornos de chamada assíncronos, ou você pode configurar uma condição de corrida. E, finalmente, seus testes certamente devem ser muito mais robustos do que isso. Em última análise, devemos estar testando com respostas de rede escarneceu e devemos saber, para cada teste, exatamente o que a resposta da rede vamos receber. Devemos testar que qualquer código que esteja fazendo o login retorna as informações corretas para nós. Há uma diferença entre o servidor que permite ao usuário fazer logon com êxito e negar o usuário com credenciais inválidas. Há também uma diferença entre credenciais inválidas e recebendo qualquer número de vários erros de servidor (mais comumente, erros no intervalo 5xx). Obter um 503 e obter uma resposta de credencial inválido estão longe de ser a mesma coisa, e seus testes devem validar youre recebendo o que você espera obter. Então, Ive basicamente disse-lhe para quebrar completamente todo o código que você escreveu. E eu aguento isso. Não há nenhuma razão para o código que você escreveu para existir. Mas, ainda podemos falar sobre algumas das questões que seu código existente tem. Este nome da função tem um nome estranho: waitFalseExpectationsUntilTimeout. É difícil para mim dizer por nome só o que esperar este método para fazer. Parece semelhante ao método waitForExpectationsWithTimeout (timeout: NSTimeInterval, handler: XCWaitCompletionHandler) existente, mas tem essa estranha gama de expectativas que eu deveria passar. O nome precisa ser melhor. Algo como assertUnfulfilledExpectationsWithTimeout. Mesmo com o nome melhor, estavam em problemas extraordinários aqui. Tanto quanto posso ver, não há nenhum meio público de verificar se ou não uma expectativa foi previamente cumprida. Seu código realmente não faz nada além de cumprir todas as expectativas no último momento antes que o teste seja concluído. Não garante que eles werent cumprido anteriormente. Esta variável merece um nome melhor, e esta lógica ou merece um comentário ou deve ser eliminada completamente. Id opt para eliminá-lo completamente e lançar uma exceção se o usuário passou um valor menor que 0,5. E, finalmente, essa lógica é, em última análise, problemática, porque você pode acabar com tempo negativo (se o tempo limite for inferior a 0,5). Você provavelmente deve optar por alguma lógica que se parece mais com isto: Finalmente, existem vários problemas com a classe aninhada: Primeiro, não precisamos marcar isso como uma função objc. Em vez disso, podemos marcá-lo como dinâmico. Segundo, foram forçados, mas não eram Jedi. Isso não passaria o meu conjunto pessoal de regras swiftlint onde força-casting é considerado um erro e se recusa a compilar. Em terceiro lugar, expc é um nome de variável sem sentido, e não há nenhum valor real em abreviando aqui. Em quarto lugar, youve misspelled cumprir, mesmo que sua grafada corretamente várias outras vezes neste contexto, em virtude de autocompletar nomes método. Em quinto lugar, por que não basta adicionar um método para a extensão para lidar com isso em vez de complicar com uma classe aninhada com um nome estranho Então, isso é uma versão significativamente mais limpa e mais segura do seu código. Mas novamente, ele doesnt realmente afirmar que essas expectativas não foram cumpridas antes de você cumpriu-los (tanto quanto sei que é impossível). E, finalmente, é um monte de código para implementar, testar, manter e verificar se ele funciona. E isso é especialmente assim quando comparamos isso com a combinação de expectativa apenas que eu esbocei no topo desta resposta. Eu queria adicionar um adendo no caso de o problema era que há um bloco de código específico que só é executado no caso de um login bem-sucedido. Se este é o cenário, existem apenas duas possibilidades. A primeira é que existem blocos separados de sucesso e falha. Algo nesse sentido: Neste caso, o essencial é aproximadamente o mesmo que o que eu descrevi no topo. Nós queremos cumprir a expectativa em ambos os blocos, mas no bloco de sucesso, bem, basta adicionar um XCTFail (o usuário foi autorizado a fazer login) para que ainda esperemos por este bloco (ou o bloco de falhas) para executar, mas se Ele toma esse caminho, falhamos pela razão específica de que o ramo errado foi inserido (ao contrário de simplesmente tomar o caminho certo, mas não levá-lo rapidamente o suficiente). O outro caso é que há apenas uma chamada de retorno para o caminho de sucesso: Se este é o projeto, eu não tenho idéia de como seu aplicativo consegue dar qualquer feedback para o usuário em tudo que algo deu errado durante o processo de login. Eu sei que você não pode modificar o código, mas você precisa estar dizendo as pessoas que podem que eles precisam para corrigir esse problema.
No comments:
Post a Comment