Primeiras aulas do curso iOS: Testando comportamentos com mocks

iOS: Testando comportamentos com mocks

Criando classes falsas - Introdução

Sejam bem vindos à segunda parte do nosso curso de testes para iOS. Nesse curso, vamos avançar nossos conhecimentos em teste. Ou seja, vamos aprender a testar classes com nível de complexidade maior, por isso recomendo que você já tenha feito a primeira parte deste curso, que é onde estudamos sobre testes de unidade e a prática do TDD. É importante você estar confortável com todo esse conteúdo, porque vamos continuar utilizando tudo que vimos na primeira parte.

Vamos começar entendendo como simular o comportamento de algumas classes. Por exemplo, vamos continuar trabalhando em cima do projeto de leilão, e vamos precisar, por exemplo, escrever um teste que encerre um leilão, que verifique o maior lance. Nesse projeto, vamos trabalhar com persistência de dados locais no nosso device, ou seja, vamos ter uma camada down.

Para um leilão ser encerrado, ele vai precisar ser salvo no banco de dados e ser atualizado como encerrado. Será que faz sentido mexer no banco de dados de produção do nosso app para conseguir realizar esse tipo de teste? Não faz sentido. Então vamos começar a pensar em outra forma quando simularmos essa classe down para conseguir fazer o teste.

A primeira abordagem que vamos ver vai ser criar classes falsas. Vou criar uma classe falsa na camada down do app que devolva objetos fixos para conseguirmos testar. Só que depois que fizermos isso vamos perceber que dá um pouco de trabalho criar essas classes falsas na mão. Por isso vamos instalar um framework que vai nos auxiliar, que se chama Cuckoo, que vai nos ajudar a criar essas classes falsas.

Com o Cuckoo, conseguimos criar mocks rapidamente. Depois, vamos aprender que para trabalhar com mocks precisamos ensinar esse mock a responder da forma que precisamos. Por exemplo, se precisarmos verificar os leiloes encerrados do banco de dados, não vou precisar de uma classe concreta. Vou criar um mock, que vou ensinar a devolver determinados objetos para que eu consiga testar o comportamento de alguma classe. É dessa forma que vamos trabalhar.

Depois, vamos aprender a verificar se métodos foram chamados. Por exemplo, para atualizar um leilão preciso chamar um método na camada down que atualize essas informações. Só que não vou utilizar a classe completa da camada down. Só vou verificar se o método que atualiza foi chamado, e não de fato vou invocar toda a lógica. Dessa forma, conseguimos realizar esse tipo de teste.

Depois vamos partir para mocks que lançam exceções. Ou seja, caso ocorra algum problema com as consultas, preciso criar um teste para verificar se meu aplicativo sabe tratar essas exceções. Por isso vamos criar mocks que lançam exceções, para não precisarmos mexer e forçar algum erro no banco de dados.

Por último, vamos aprender a testar o view controller e levantar a questão de quando devemos criar mocks e quando não devemos. Esse é o conteúdo que vamos ver nessa segunda parte. Espero você.

Criando classes falsas - Testando o encerrador de leilão

Essa é a segunda parte do nosso curso de testes para iOS. Vamos avançar os nossos conhecimentos em teste e aprender a criar coisas mais complexas. Para isso, vamos continuar utilizando o projeto do curso anterior, que é o leilão. Só que para ganhar tempo adicionei algumas classes e vou pedir para que vocês façam o download novamente.

Logo de cara, vou abrir a pasta models e vou começar a analisar a classe encerrador de leilão. Como o próprio nome sugere, a função principal dela é encerrar leilões. O método encerra cria uma constante chamada dão, instância esse leilaodao, ou seja, a partir de agora estamos mexendo com persistência local no nosso device. Embaixo ele cria uma constante chamada todos os leilões correntes. Chama o dao.correntes e faz um for para percorrer toda a lista. Ele verifica se o leilão começou semana passada, ou seja, se é um leilão antigo. Se for, ele vai encerrar esse leilão, vai somar um e atualizar no banco de dados.

Agora que entendemos o que esse método encerra faz, precisamos testar para ver se realmente ele está encerrando leilões que começaram uma semana antes. Para começar a testar, vou criar uma nova classe de teste, na opção unit test case class. Com ela selecionada, vou dar o next, e em classe precisamos de um nome para ela. Já discutimos no curso anterior que é uma boa prática manter o mesmo nome da classe em produção, que no caso é encerrador de leilão, mais o sufixo teste.

Ele já traz vários métodos. Vamos apagar os dois últimos, que não vamos utilizar, e também vamos aproveitar para apagar os comentários. O primeiro método de teste que vamos criar vai ser deve encerrar leilões que começaram uma semana antes.

Repare que a nomenclatura ficou longa, mas também já comentamos no curso anterior que não tem problema criar métodos com nomes longos nas classes de teste, porque serve para documentar e entender o que a classe de produção está fazendo.

Para conseguir testar se um leilão foi encerrado ou não, primeiro precisamos criar uma data antiga, porque nosso encerrador de leilão verifica se o leilão começou na semana passada. Para conseguir criar essa data, vou começar com um date formatter, que é um formatador de datas. Depois, vou passar um formato para essa data. Ele vai ser ano, mês e dia.

Agora sim podemos criar a data. A data antiga é igual ao formatador que criamos lá em cima ponto date. Estamos criando com o guard let porque o date é opcional. Ele vai tentar criar essa data. Para não trabalhar com variáveis do tipo optional, estou criando um guard let.

Temos que seguir o mesmo formato que criamos lá em cima. Primeiro o ano, que pode ser 2018, depois o mês e o dia. A data vai ser 09/05/2018. Preciso colocar a condição de else com return.

Agora, precisamos criar os leilões. Vou chamar, por exemplo, de tvLed é igual a criador de leilão. Repare que não temos acesso porque precisamos importar as classes do projeto. Lá em cima, digito @testable import e o nome do projeto. Depois posso chamar o criador de leilão, para o nome do produto, e depois a data.

Vamos aproveitar e criar outro leilão também, por exemplo, de uma geladeira. Temos então dois leilões. O próximo passo é chamar o encerrador. Eu vou chamar o encerrador ponto encerra.

Agora precisamos fazer a verificação e ver se o tvLed.encerrado, que é uma variável booleana que ele retorna, é verdadeira. Só que repare que ele também é opcional. Vamos extrair o valor para conseguir fazer o asset. Se não conseguir, damos um return. Embaixo a mesma coisa com a geladeira.

Precisamos fazer a asserção, passando o status do produto. Tem que estar true se nosso encerrador de leilão funcionar. Rodando o teste, tem algumas falhas.

Nós criamos dois produtos, e embaixo chamamos o encerrador. Só que a classe encerrador de leilão, com esse método encerra, chama o dao.correntes. Ele pega do banco de dados todos os leilões correntes para aí sim verificar se o leilão é antigo ou não. Ou seja, o teste não está falhando porque os produtos não estão salvos no banco de dados. Apenas criamos eles, e na hora que ele chama esse método ele não encontra nenhum produto.

Vamos voltar ao teste e salvar os produtos no banco de dados, porque precisamos fazer o teste passar. Vou pegar o dao.salva e vou passar a tvLed e a geladeira. Depois que eu salvei no banco de dados, ele vai encerrar o leilão. Nesse momento, já é para aparecer a tvLed e a geladeira. Só que agora, para conseguir testar, vou precisar recuperar novamente do banco de dados.

Vou tirar esses dois guard let que criamos e vou começar a verificar de outra forma. Como temos uma lista, primeiro vou verificar o valor dela. O número de elementos que tem dentro dela. E depois passo leilões encerrados ponto count. Dentro do asset true, vou pegar leilões encerrados, o elemento da primeira posição desse array, e vou pegar um isEncerrado. A mesma coisa embaixo.

Nosso teste passou. Realmente estamos conseguindo encerrar o leilão. Rodando novamente, sem mexer em nada, ele falha. Nosso framework de teste diz que esperava dois objetos e vieram quatro. O problema é que na primeira vez funcionou porque criamos a tvLed e a geladeira, e como não tinha nada no banco de dados ele salvou esses dois produtos. Quando ele foi fazer a verificação, tinha que ter a geladeira e a tvLed. Só que quando rodamos o teste pela segunda vez a tvLed e a geladeira já estavam lá, mais os dois produtos que criamos. Toda vez que rodarmos o teste ele vai adicionar dois produtos e muda o cenário.

Será que essa é a melhor forma de testar?

Criando classes falsas - Criando classe falsa

Nós acabamos de escrever um teste para verificar se o método encerra realmente está funcionando. Porém nos deparamos com um problema. Nós estamos executando o teste e salvando os objetos que estamos utilizando para testar de verdade no banco de dados do nosso aplicativo. Cada vez que executamos os testes, são incluídos dois objetos no banco de dados, e isso muda o cenário do teste.

Faz sentido salvar esses objetos de teste no banco de dados de verdade do nosso aplicativo? Não. Mas então como testar o comportamento da classe encerrador de leilão sem salvar os objetos de verdade no banco de dados? Poderíamos por exemplo criar uma classe falsa para simular esse comportamento. Mesmo assim, conseguiríamos testar o comportamento da classe.

Na pasta dao, vou criar uma nova classe. Ele traz um arquivo em branco, a ideia é ter os mesmos métodos da classe leilaodao sem salvar no banco de dados. Se eu entrar na classe leilaodao, temos por exemplo o método salva, que utilizamos para testar. Vamos chamar o dao falso e depois o método salva.

Vou receber um leilão por parâmetro e em cima vou criar uma variável que vai ser uma lista chamada leilão, e vou inicializar vazia. No método salva, não vamos iniciar isso no banco de dados. Vou pegar a lista de leilões que acabei de criar e vou adicionar o elemento. E aí vou adicionar o objeto que estou recebendo por parâmetro.

Além do método salva vamos precisar do método encerrados. Que vamos utilizar para ter a lista de leilões encerrados. Vamos criar esse método. Ele vai devolver uma lista de leilão. A ideia é retornar a lista de leilões. Só que queremos só os encerrados. Vamos fazer um filtro.

Além do método encerrados nós também precisamos do método correntes, porque vamos utilizar no encerrador de leilão. Ele tem o método correntes. Vamos voltar no leilaodao.falso e criar o método. Vou devolver também uma lista de leilão. Aqui vou filtrar os leilões que tem a variável encerrado igual a false.

Para finaliza, também tem o método atualiza, que vai receber um leilão, nele não vamos fazer nada, vamos apenas criar, porque vamos utilizar na classe encerrador de leilão.

Temos uma classe falsa, que vai simular a classe concreta do banco de dados, e precisamos utilizar a classe. Onde estou criando a constante dao, vou trocar o let dao igual a leilaodao por leilaodaofalso.

Nosso teste falhou. Vamos entender. Ele disse que espera dois elementos dentro da lista e vieram dez. Eu rodei os testes e ele continuou acumulando elementos no banco de dados. Se já instanciamos o leilaodaofalse, deveria estar funcionando.

Embaixo, estamos instanciando a classe encerrador de leilão e chamando o método encerra. Ele logo de cara instância a classe concreta. Aqui está o problema. Estamos instanciando, porém aquele daofalse não está sendo utilizado, porque ele está instanciado o leilaodao. Será que faz sentido? Na verdade, ela só precisa utilizar o leilaodao. Não faz sentido instanciar. Aí entra o conceito de injeção de dependências. Vamos tirar a instanciação da classe leilaodao desse método encerra e vamos receber essa dependência no método construtor da classe. Vou colocar o tipo leilaodaofalso. Não tem problema, porque estamos apenas testando se faz sentido trabalhar com essas classes falsas, depois mudamos.

No método construtor da classe encerrar de leilão, estou recebendo o leilaodao, e agora vou guardar um atributo da classe, que é do tipo leilaodaofalso. Depois, coloco que self.dao é igual ao leilaodao que estou recebendo por parâmetro. Dessa forma, não preciso mais instanciar esse objeto nessa classe encerrador de leilão.

Agora que tenho o método construtor onde estou esperando o leilaodao, preciso ir no teste e injetar o daofalso, que acabamos de criar. Agora nosso teste passou. Dessa forma, estamos injetando o daofalso na classe encerrador de leilão e continuamos utilizando o dão que recebemos por parâmetro. Faz sentido realmente trabalhar com essas classes falsas.

Sobre o curso iOS: Testando comportamentos com mocks

O curso iOS: Testando comportamentos com mocks possui 166 minutos de vídeos, em um total de 37 atividades. Gostou? Conheça nossos outros cursos de iOS em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda iOS acessando integralmente esse e outros cursos, comece hoje!

  • 1150 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

Premium

  • 1150 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$75
à vista R$900
Matricule-se

Premium Plus

  • 1150 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$100
à vista R$1.200
Matricule-se

Max

  • 1150 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$120
à vista R$1.440
Matricule-se
Procurando planos para empresas?
Acesso por 1 ano
Estude 24h/dia onde e quando quiser
Novos cursos toda semana