Concrete Logo
Hamburger button

Como desenvolver app iOS com TDD, cobertura e Integração Contínua – Parte 2

  • Blog
  • 12 de Fevereiro de 2014
Share

Esta é a segunda parte de uma série de quatro posts sobre desenvolvimento de app iOS com TDD e integração contínua que vamos compartilhar aqui no Blog nas próximas semanas. Se você perdeu a primeira parte, aqui está o link. O foco desse segundo post será construir a app e, mais importante, testá-la. De novo vou dividir em passos e seguir uma linha de TDD (criando os testes primeiro) para mostrar
como é fácil e intuitivo esse approach com Specta. O ideal para seguir esse tutorial é baixar a app e analisar o código e os testes para entender o que está acontecendo. Durante o post vou ressaltar as partes mais relevantes, mas o contato com o código é fundamental e a simples leitura do post, “without getting your hands dirty” não acrescenta muito. Vamos lá: Passo 0 1. Crie um storyboard e o configure como main interface na aba General do projeto. 2. Adicione um navigation controller e uma view controller. Neste Passo, criaremos uma classe ShotsListViewController e setaremos a CustomClass da view controller do storyboard para nossa classe ShotsListViewController.

Passo 2

Feito isso, em uma abordagem tradicional começaríamos a adicionar código na view controller, ligar os outlets e coisas do tipo. Mas vamos ter a disciplina de começar pelo teste para gerar um hábito.

3. Crie o Arquivo ShotsListViewControllerSpec e comece a escrever seus testes. Preste atenção na configuração do beforeEach que será rodado antes de cada teste (um setUp estilo XUnit), ele contém passos necessários para carregar a view e chamadas que carregam os outlets e constroem a view na view controller. Sem esses passos não será possível testar os outlets e outras partes do seu view controller, dando a impressão de que o código está errado. Por isso, adicionei a chamada à view e o expect para verificar se a mesma não está nula no bloco do beforeEach.

Passo 3

Rode os testes e verfique se está tudo certo. Dica: é legal sempre rodar os testes antes de implementar, para vê-los falhando. Caso contrário você pode acabar com um falso positivo.

Passo 3.2

4. Adicione mais alguns testes para garantir que a view controller tenha uma propriedade de tableView e que ele possui o datasource e delegate amarrados. A essa altura, o compilador vai começar a reclamar pois não temos uma propriedade shotsTableView na view controller. Defina a mesma e rode os testes. Passo 4 Nenhum vai passar. Agora precisamos adicionar a tableview no storyboard e amarrar os outlets, datasource e delegate. Além disso, precisamos adicionar os protocolos na declaração da ShotsListViewController. Feito isso, os testes irão passar sem problema. 5. Como se trata de um viewController para carregar shots (algo como Posts do Dribbble), cedo ou tarde precisaremos de uma maneira de carregar tais dados. Agora entra a parte legal: usaremos um serviço para encapsular os detalhes da implementação da viewController. Antes de escrevermos qualquer linha de código, vamos testar usando mocks e stubs. OCMock é um framework excelente para esse trabalho. A test case Na primeira linha do beforeEach, criamos um mock para o ShotService (classe que eu criei para ser o ponto de interface entre a viewController e o carregamento dos dados), dessa forma não preciso me preocupar como este carregamento vai ser feito. Porém, só criar o mock não basta, precisamos de uma maneira de usá-lo na viewController. A segunda linha do beforeEach endereça esse problema. Comumente chamado de setter injection, é uma maneira de dizer para a viewController usar o nosso mock ao invés da implementação concreta da classe de serviço. No primeiro teste estamos fazendo um mock para a chamada de fetchShotsList, com qualquer argumento ou bloco. Após mockarmos o método, chamamos o viewDidLoad do ViewController que será o responsável por chamar esse método mockado e verificamos se ele foi chamado no afterEach. Dessa forma, acabamos de garantir que toda vez que o viewDidLoad da classe ShotsListViewController seja chamado ele fará o fectchShotsList usando o ShotsService. *Essa forma de montar o teste é conhecido como Arrange-act-Assert pattern. O segundo teste difere um pouco do primeiro. O que ele faz na verdade é um stub, em outras palavras, quando esse método for chamado com qualquer argumento responda com esse bloco. O bloco, no caso, é apenas uma maneira de criarmos a “Data”, o array de shots, sem precisar  ir na internet, banco de dados ou qualquer outra forma que nos faça precisar conhecer a implementação. Após esse stub, testamos se o datasource foi corretamente carregado. Não seria viável mostrar todos os exemplos de testes feitos no projeto aqui nesse post, mas acredito que a ideia foi passada. Dentro do projeto encontram-se inúmeros exemplos de como testar os models e células da tabela, como criar factories para servir de fake data objetcs usados nos teste, entre outros. O ideal é que o projeto seja clonado e alterado para total entendimento de como as coisas funcionam.  Escrever testes em iOS nunca foi tão facil, com Specta, Expecta e OCMock, praticamente podemos testar qualquer ponto da aplicação. Portanto, as desculpas para não testar aplicações iOS já não existem mais. Por último, uma preferência pessoal de como estruturar as pastas do projeto (um plus, já que nesse departamento cada um tem suas preferências). Essa é a forma que eu estruturei esse projeto: ÚltimoAlguma dúvida até aqui? Deixe seus comentários!

Update: continue aprendendo sobre integração contínua para iOS na parte 3 desta série.