3.5 Teste de Unidade e a Evolução do Sistema
Na seção anterior, iniciamos a escrita de um teste funcional que buscava um site que apresentasse título "To-Do" que não foi encontrado e, desse modo, o teste falhou.
Nesta seção, daremos início à construção da aplicação de forma mais acelerada e, para isso, iremos combinar dois tipos de testes, conforme sugerido por Percival (2017) na implantação de sua estratégia de TDD. Mais detalhes do ciclo TDD sugerido por Percival (2017) será apresentado mais adiante. O primeiro passo, entretanto, é configurar a aplicação no Django.
Primeira aplicação Django
Considerando o nosso diretório de trabalho, conforme ilustrado abaixo, estando no diretório contendo o arquivo manage.py
.
Estando nessa pasta de trabalho, vamos executar o comando para a criação de um projeto em Django. O Djando enfatiza a organização do código dos projetos em aplicações. Ao executar o comando da linha 1, python manage.py startapp lists
, será criada a aplicação superlists/lists
, ao lado da pasta superlists/superlists
, conforme ilustrado abaixo.
Como pode ser observado na estrutura de diretórios acima, o Django estrutura a aplicação segundo o padrão MVC (Model-View-Controller), e gerou arquivos que representam tal padrão. No nosso caso, o arquivo de maior interesse nesse momento é o arquivo tests.py
(linha 13).
Combinando Testes Funcionais e Testes Unitários no TDD
A abordagem de TDD adotada por Percival (2017) segue a seguinte filosofia: testes funcionais testam a aplicação a partir do lado externo, do ponto de vista do usuário; e os testes unitários testam a aplicação do ponto de vista do programador. O ciclo do TDD preconizado por Percival (2017) é detalhado abaixo:
Iniciamos escrevendo um teste funcional que descreve uma nova funcionalidade do ponto de vista do usuário;
Em posse do teste funcional que falhe, começamos a pensar em como devemos escrever o código da aplicação para fazê-lo passar ou pelo menos chegar mais próximo da solução para fazê-lo passar. Para isso, usaremos nesse momento,um ou mais testes de unidade para definir como queremos o código das partes que irão compor nossa solução. A intenção é que cada linha do código de produção seja executada por ao menos um teste de unidade;
Tendo o teste de unidade que falhe escrevemos a menor quantidade possível de código da aplicação para fazer o teste passar. Pode ser necessário que os passos 2 e 3 se repitam algumas vezes até que ocorra um avanço em relação ao teste funcional criado no passo 1;
Ao final do ciclo dos passos 2 e 3 é possível executar novamente o teste funcional e verificar se ele também passa, ou se avança um pouco. Isso pode exigir que sejam escritos mais testes de unidade e mais código da aplicação, e assim sucessivamente.
Como comentado por Percival (2017), esse ciclo e combinação de testes funcionais e testes de unidade podem parecer redundante mas o objetivo de cada tipo de teste é bem definido e são distintos.
"Os testes funcionais devem ajudar você a construir uma aplicação com as funcionalidades corretas e garantir que você não causará falhas acidentalmente. Os testes de unidade deveriam ajudá-lo a escrever um código que seja limpo e livre de defeitos." (Percival, 2017)
Teste de Unidade no Django
Nessa seção veremos como escrever um teste unitário para view criada pelo Django. O template do teste unitário criado pelo Django é ilustrado abaixo:
Como observado na linha 2, o Django utiliza uma classe TestCase
que é uma versão estendida da classe unittest.TestCase
. Essa classe possui alguns recursos adicionais específicos do Django que faremos uso no restante deste capítulo.
Para iniciarmos, vamos redigir um teste que falhe propositalmente para verificar se o ambiente de execução está funcionando corretamente. Desse modo, o arquivo lists/tests.py
foi alterado conforme abaixo:
A execução desse teste é feita conforme abaixo:
Observe que diferentemente do functional_tests.py
que era executado diretamente, o teste do Django é executado de forma diferente, com o comando python manage.py test
. Com o resultado acima o executor parece funcionar normalmente e esse é um bom momento para colocarmos nosso projeto sob controle de versão. Os passos para isso, adaptados de Percival (2017), são dados abaixo:
Explicação Básica sobre Django
Conforme mencionado anteriormente, o Django está estruturado conforme o padrão MVC. Desse modo, ele tem modelos mas, conforme comentado por Percival (2017), suas views estão mais para controladores, e são os templates que, na verdade, compõem a visão. De modo geral, como qualquer servidor Web, o papel principal do Django é decidir o que fazer ao receber uma requisição via URL.
O fluxo do Django pode ser resumido a (Percival, 2017):
Uma requisição HTTP chega a um URL específico;
O Django utiliza algumas regras para decidir qual função de view deve lidar com a requisição, ou seja, resolver a URL;
A função view processa a requisição e devolve uma resposta HTTP.
Desse modo, pensando no nosso teste, dois pontos precisam ser testados (Percival, 2017):
Podemos resolver o URL da raiz do site ("/") para uma determinada função de view que criamos?
Podemos fazer essa função de view devolver um pouco de HTML que fará o teste funcional passar?
Para resolver o primeiro ponto, alteramos o nosso teste lists/tests.py
conforme abaixo:
Em relação ao código acima, a chamada da linha 8, resolve('/')
, é uma função interna do Django que resolve um URL para descobrir qual função de view deve tratar a requisição. No exemplo, quando chamada com '/'
, que é a raiz do site, esperamos que tal URL seja resolvida para a função home_page
.
Como podemos observar ao executar esse teste, a função home_page
ainda não está implementada (mensagem das linha 15 e 16) e, portanto, o teste ainda falha.
Iniciando a Escrita de Código da Aplicação
Como observado no exemplo acima, o teste ainda falha pois não existe uma função de views responsável por tratar determinada URL. Para fornecer uma implementação para isso devemos editar o arquivo lists/views.py
. Tentando fazer o mínimo necessário para fazer o teste passar, o código abaixo é uma tentativa de solução.
Ao executar o teste novamente, o resultado é exibido abaixo:
Ainda não foi dessa fez que nosso teste passou e Percival (2017) nos alerta que temos que aprender a ler as mensagens de erro para nos ajudar a compreender o que ocorreu e tentar corrigir o código da aplicação para que o nosso teste passe.
O primeiro ponto a ser observado é o erro que ocorreu (linha 16). Em geral, ele deveria ser o suficiente para compreendermos o problema e fazermos as devidas correções mas, nesse caso, ele parece meio complicado.
O segundo ponto a ser verificado é qual teste está falhando (linha 6). Nesse caso é o que esperávamos.
O terceiro ponto é verificar o que está causando o erro e, no exemplo, é a chamada ao resolve('/')
(linha 11). Nesse caso, ao tentar resolver o URL fornecido, o Django está devolvendo um erro 404.
urls.py
Conforme observamos no erro acima, os testes indicam que precisamos de um mapeamento de URL. Isso é feito em Django no arquivo urls.py
, que organiza os mapeamentos entre URLs e funções de view.
Há um arquivo urls.py
para todo site e ele está localizado na pasta superlists/superlists
. Para resolver o problema momentaneamente vamos alterá-lo conforme abaixo:
Além dos comentários que nos ajudam a compreender como alterar o código, o código acima apresenta como o Django faz os mapeamentos. Basicamente, na linha 21, o primeiro parâmetro é uma string utilizada para indicar quais URLs atendem ao padrão desejado e, os demais, indicam quais funções de view são chamada.
Para atender as nossas necessidades, vamos utilizar as instruções presentes nas linhas 7 e 8 (comentário acima), mapeando para o nosso exemplo.
Ao executar os testes agora temos o seguinte resultado:
O trace do erro é longo e a maior parte foi omitida. Observe, entretanto, que não temos mais um erro 404. O problema agora é que, ao resolver o URL deveríamos encontrar uma função de view e o que temos até o momento é apenas uma variável. Vamos corrigir isso alterando o arquivo lists/views.py
com o conteúdo abaixo:
Finalmente, o resultado da execução do teste passou, conforme apresentado abaixo:
Como chegamos a um resultado satisfatório até aqui é hora de confirmarmos nossas e colocar o código alterado sob controle de versão.
O primeiro comando é uma forma rápida de adicionar as alterações e já confirmar. O segundo envia as alterações para o GitHub.
Last updated