Concrete Logo
Hamburger button

Criando um aplicativo com boas práticas em Swift (Parte 1)

  • Blog
  • 23 de Agosto de 2016
Share

Recentemente, tenho estudado um pouco sobre como criar um aplicativo em Swift. Depois de ler diversas fontes, resolvi compartilhar com vocês um compilado de tudo o que aprendi e do que entendo hoje como boas práticas em dois posts aqui no Blog. A ideia completa da série é criar um aplicativo iOS escrito em Swift e tentar destrinchar cada parte criada, testar e apresentar a vocês.

Para começar, escolhi a camada de serviço Moya, uma ótima ferramenta de abstração para o Alamofire ou, como eles mesmo dizem:

So the basic idea of Moya is that we want some network abstraction layer that sufficiently encapsulates actually calling Alamofire directly. It should be simple enough that common things are easy, but comprehensive enough that complicated things are also easy.

Para testes vou usar Quick, Nimble e OHHTTPStubs. O Quick e o Nimble são frameworks que trouxeram a ideia do Specta e Expecta do Objective-C para o Swift, que na minha opinião utilizam uma sintaxe mais clara para os testes como expect (Exemplo: expect(2).to(equal(2))) para comparação e separação em blocos dos testes.

Lembrando que a ideia desses posts não é se aprofundar nos frameworks usados, mas vou tentar deixar todas as fontes para buscas. Ok?

No serviço, temos a classe que implementa TargetType do Moya, e como sua implementação está na documentação do Framework, vamos pular direto para o BaseService. Aqui teremos um protocolo, que define o método handleError,  e uma extensão, que implementa esse método. Ele será útil para reutilização do Switch de Errors que veremos mais à frente, já que todos os serviços implementarão BaseService, o que permitirá a utilização desse método por eles.

 

Para auxiliar o serviço, temos dois enums: Errors e Results, que tornarão o retorno do nosso serviço genérico. O Result com Success(T) ou Failure(Error) e o Errors implementando ErrorType para mapear tipos de erros possíveis

Result:

 

Errors:

 

Isso nos leva ao ShotService, onde a mágica acontece (rs). O ShotService herda de BaseService e implementa Gettable (Orientação a Protocolo que falarei mais para frente em outro post).

 

Para chamar o serviço, o Moya pede que instanciemos o MoyaProvider passando nossa implementação de TargetType como genérico, o que permitirá fazer o request com o enum do endpoint desejado (Veja a documentação do Moya para mais informações).

No serviço tem o método get que espera uma Closure chamada completion, que por sua vez retorna o Result, no qual a implementação do genérico, nesse caso, será um array de Shot ([Shot]), o que esperamos em caso de sucesso.

Nesse método, faremos o request do Moya e o seu resultado será tratado. Em caso de sucesso, faremos o parse do objeto JSON com o Moya_ModelMapper que, dada a possibilidade de jogar uma exceção, será tratado com do/catch. Esse objeto será retornado pelo nosso Result.success(T). Caso algum erro diferente de 200 seja recebido, o método handlerError do Base Service será chamado para identificar qual Errors enviar ao completion.

Com essa estrutura, temos um código com resultados genéricos e podemos tratar os tipos de erros esperados na aplicação, o que vai facilitar mais à frente, quando usarmos esse serviço.

Para terminar, vamos testar nosso serviço com o OHHTTPStub. A ferramenta vai criar uma chamada Stub ao request do Moya (uma resposta fake para a chamada do método). Não vou me  preocupar em cobrir todo o código escrito, mas sim em fomentar a ideia de testes com uma tentativa de ajudá-los a começar.

Queria lembrar que também não vou me aprofundar na estrutura usada pelos frameworks, e sim nos testes. Para começar, antes de cada execução realizaremos um stub do request, que permitirá utilizarmos como resposta o mock que quisermos. Para esse teste produziremos um caso de sucesso com um array no formato json (BaseAPI.shots(id: nil).sampleData vide documentação do Moya) e status code 200.

 

Tendo isso, saberemos que ao chamar o método get do nosso ShotService o caso de sucesso será chamado e o parse do objeto deverá ser feito sem falhas, ou seja, nossa expectativa é que tudo ocorra como planejado no método e ele retorne exatamente o que esperamos, um Array de Shot. Então, poderemos validar sua quantidade e ainda validar se o objeto é o esperado.

 

Com isso, garantimos que o sucesso do teste está de acordo com o esperado e, mesmo refatorando o método get, ele deve garantir esse “contrato” (o teste) para que seja validado. Isso mostra a importância dos testes.

Para finalizar essa primeira parte da série,  deixo como desafio garantir a cobertura do nosso serviço. Para isso, todas a condições do método get devem ser validadas, portanto deverão ser criados novos Stubs do request para que cada parte seja garantida pelo teste.

Ficou alguma dúvida ou tem algo a sugerir? Fique à vontade nos campos abaixo! Amanhã eu volto para mostrar uma arquitetura MVP aplicada a Swift. Até lá!