Testando ApolloGraphQL Subscriptions no Android + Kotlin Flow + Turbine

Diego Cunha
Android Dev BR
4 min readMay 14, 2021

--

No mundo de hoje, quando pensamos em comunicação em tempo real, nós de tecnologia pensamos automaticamente em WebSockets e com isso podemos criar um mundo fantástico onde tudo acontece em tempo real e no mundo do desenvolvimento mobile temos muita preocupação com isso, pois nos dias de hoje tudo se resume a informação em tempo real então para nós WebSockets é basicamente mandatório para desenvolver um aplicativo em destaque.

wAqui na Warren, dentro da squad Trade nós utilizamos o GraphQL para trabalhar com dados e para nossas cotações em tempo real nós utilizamos o conceito de subscriptions que é na sua mais pura e simples explicação um WSS com todo o poder do GraphQL que só nos mapeia o que pedimos para ser usado nas telas e consumimos de acordo com nossa necessidade.

O Contexto

Para lidar com o GraphQL, nós utilizamos o ApolloGraphQL para lidar com o mapeamento e carregamento dos dados e nele também mapeamos nossas Subscriptions e dentro desta biblioteca temos a principal Extension Function para o universo Android/Kotlin que é .toFlow(), ela resumidamente cria um callBackFlow e fica responsável por emitir os estados recebidos do WebSocket com toda a liberdade de threads que o Flow nos porporciona.

Como bons desenvolvedores, nós devemos criar testes unitários para esperar que os comportamentos esperados para nossa camada de ViewModel esteja de acordo com o que esperamos e que nossa camada provedora de dados esteja realizando os mapeamentos e construções corretamente, abaixo segue um exemplo resumido do nosso tratamento de cada emit que o Apollo realiza, ou seja, a cada ping que o socket.

Resumindo o código acima, a cada emissão de dados, convertemos para um modelo de dados interno nosso com um conversor e emitimos esse resultado para o responsável para consumir o dado responsável.

O cenário

Com isso definido, temos que converter para um modelo de dados que nos permita para um modelo de dados testável e que faça sentido para nós e no exemplo de baixo seguimos um pouco esse padrão, com ele nós mapeamos o modelo de dados que temos para um Resource que possuí estado de erro e sucesso (assim como os Results nos exemplos da Google).

No desenvolvimento das Subscriptions, percebemos que podiam haver alguns pontos complicados de compreensão e desenvolvimento da funcionalidade por ser algo relativamente novo no mundo da tecnologia, tão novo que nem a própria responsável pelo GraphQL apoia o uso de Subscriptions em ambientes de produção na sua forma pura, como você pode ler aqui.

Por fim chegamos a fase mais importante e motivo deste artigo, por um tempo considerável nós acabamos deixamos os testes unitários disto para um segundo momento, o que não é uma boa prática mas foi um mal necessário para o momento mas os problemas acabaram graças ao Turbine. Esta biblioteca de testes de código aberta 100% escrita em Kotlin que tem como função auxiliar desenvolvedores testarem comportamentos do Flow e entender na forma mais simples como as coisas devem ser testadas e auxiliar desenvolvedores de forma mais clara como os testes devem ser escritos.

Testando cenário de erro na Subscription

Todo o cenário descrito nesta seção é baseada no código abaixo que é apenas um teste unitário para um cenário de erro comum dando um throw Exception() simples.

Um problema comum nos desenvolvimentos de testes que o Kotlin gera é sobre como criar mocks de Extension Functions e graças ao Mockk nós temos uma maneira que não é a melhor maneira mas é como eles nos ensinam em como criar esses mocks.

Após isto não existe muito o que falar sobre o teste, devemos criar um mock para quando o método (que é basicamente como o Apollo monta a Subscription) devemos retornar um flow que gera uma exceção simples e com auxilio do Turbine analisar os testes e os comportamentos esperados. A principal ideia que devemos lidar é sempre imaginar que o Flow deve terminar completamente, visto que nada gerou uma exceção para o flow e sim um Resource.Error e devemos validar que o item coletado é do tipo erro.

Testando cenário de sucesso na Subscription

O cenário de sucesso de uma Subscription na camada de ViewModel pode ser analisado da seguinte maneira:

Como podemos ver, na camada de ViewModel, nós estamos nos utilizando do LiveData para prover coletar os dados do Flow e emitir para a camada de View, isto é importante pois por definições, como o LiveData sempre trabalha na Main Thread ela deve ser responsável por lidar com dados que serão enviados para Fragments e Activities e deixar o Flow lidar com a comunicação ViewModel <> Model.

No teste, nos emitimos um sucesso com uma lista de atualizações, e validamos que o ViewModel está realizando a coleta corretamente dos campos esperados e mapeando para a View atualizar os campos corretamente.

Conclusão

Como podemos ver, o Flow está cada vez mais se tornando a ferramenta poderosa que os desenvolvedores querem, seja para ter o controle de threads, seja para não precisarmos mais de bibliotecas externas para controlar fluxos de sockets e testar seus comportamentos é indispensável para garantir integridade dos dados e o consumo correto dos mesmos.

--

--

Diego Cunha
Android Dev BR

Android Developer/Amateur Master Chef/Coffe Maker/Nintendo Switch Evangelist