TDD com Flask e Unittest
Ao criar um projeto de software é inegável que desenvolver em paralelo os testes unitários garante a qualidade do código e evita o trabalho dobrado. Quando trabalhamos com Python podemos criar os testes de forma fácil utilizando o módulo unittest. Esse módulo é nativo e possui uma documentação bem detalhada de como utilizá-lo.
Nesse artigo vou mostrar como instalar as dependências necessárias para criarmos uma aplicação web com Flask, além de criar os testes unitários utilizando o unittest. Este guia pode ser seguido em todas a plataformas, entretanto usarei como base o Ubuntu 16.04 e a forma de instalar as dependências pode ser diferente em outros sistemas operacionais.
O primeiro passo para começar a criação da aplicação é instalar o Python 3 e o pip 3. Precisaremos do pip pois iremos utilizá-lo para instalar os pacotes necessários para a aplicação. No linux utilizamos os seguintes comandos para instalar o Python e o pip:
Com as primeiras dependências instaladas é possível instalar o Flask e o Pytest para podermos iniciar a criação da nossa aplicação web. Para evitar podermos ter controle sobre as bibliotecas instaladas na nossa máquina e isolar nossa aplicação em um ambiente de execução separado, vamos utilizar o setup virtualenv + virtualenv wrapper. Caso você não tenha eles instalados você pode seguir este guia onde explico como instalar e utilizar.
Supondo que você já tenha instalado o virtualenv na sua máquina, vamos criar um ambiente virtual para podermos instalar as bibliotecas do projeto. Para isso, no terminal colocamos o seguinte comando:
Se tudo correr bem, é possível ver no terminal que o nosso ambiente está ativado (flask). O nome no começo do cursor do terminal indica que estamos trabalhando em um ambiente virtual. A partir de agora, todos os pacotes que instalarmos utilizando o pip estarão isolados no ambiente virtual que foi criado e serão deletados da máquina quando ele for removido.
Com o ambiente virtual ativado, podemos instalar o Flask , o Pytest e uma outra biblioteca chamada Coverage, que mostra a porcentagem do código coberta por testes. Para isso utilizamos o pip.
Agora que as bibliotecas necessárias estão instaladas no ambiente virtual, podemos então criar a aplicação web e começar a fazer os testes. O projeto que vamos criar tem a seguinte estrutura.
--- /flask-tdd/
| --- app.py
| --- test_core.py
Para facilitar, use este comando para criar a pasta e os arquivos de forma automática.
É importante que o arquivo que contem os testes comece com “test” pois o Pytest ira varrer a pasta do projeto e executar todos os arquivos que tiverem este prefixo.
Vamos abrir o arquivo test_core.py e escrever os primeiros testes da aplicação que vamos construir.
Cada endpoint da aplicação criada pode possuir um ou mais testes. Para isso criamos uma classe principal que representa os testes do endpoint home (“/”), e dentro dela criamos os testes que são necessários para validar o código.
Vale ressaltar que as funções dentro da classe podem e devem ter nomes expressivos para mostrar qual caso ela esta testando. Assim, uma função com o nome “test_if_home_returns_ok_string” é recomendável para que o programador entenda de primeira qual caso esta sendo testado.
Com os primeiros testes feitos, podemos executá-los e ver qual resposta temos.
Assim que executamos o Pytest dentro da pasta que contem o nosso projeto ja recebemos o primeiro erro. Este erro entretanto não está relacionado aos testes em si, mas ao fato de ainda não termos criado a base da aplicação web.
Desta forma vamos criar dentro do arquivo app.py o básico da aplicação web com o endpoint home (“/”).
Com o código acima, nós criamos um hello world com o flask, ou seja, ao acessarmos a url raiz “/” iremos receber como retorno a string “Hello World”. Desta forma, como já temos uma aplicação funcional, ao executarmos os testes novamente obtemos a seguinte saída:
Como agora a aplicação esta configurada corretamente é possível ver na última linha que ela passou em 2 dos 3 testes. Além disso, é possível ver onde nossa aplicação falhou, pois é mostrado um AssertionError na linha 27. Esta linha testa o retorno de texto da aplicação, comparando se a string “ok” esta presente na resposta. Como nós definimos que a resposta seria “Hello World”, o teste falhou.
Vamos então corrigir a aplicação, remover o retorno “Hello World”, colocar “ok” e executar os testes novamente.
Agora podemos ver que a aplicação passou nos 3 testes criados.
Existem diversas formas de utilizar a biblioteca unittest. Ela fornece para o programador muitas ferramentas para testar diversas situações. Neste exemplo foi utilizado apenas o assertEqual para comparar dois valores, entretanto a documentação da unittest mostra detalhadamente todos os métodos disponíveis para comparação de dados. Você pode conferir a documentação completa aqui.
Como nós também instalamos a biblioteca coverage, podemos executar os testes e receber um relatório da porcentagem de código coberta com testes. Para gerar este relatório basta executar o pytest com o parametro “cov”.
É possível observar a aplicação app.py e no final da linha a porcentagem. Caso seja adicionada outra funcionalidade na aplicação e não haja um teste para ela dentro do arquivo de teste, essa porcentagem irá cair. Desta forma, vamos criar outro endpoint na aplicação app.py e executar novamente os testes.
Embora a aplicação tenha passado nos 3 testes novamente, é possível observar que apenas 83% do código está coberto. Isso ocorreu devido ao fato de ter sido adicionado um novo endpoint na aplicação que não possui casos de teste.