Criando uma primeira aplicação com Django e mysql
Testes automatizados 02
https://docs.djangoproject.com/pt-br/1.11/intro/tutorial05/
Apresentando testes automatizados
Escrevendo nosso primeiro teste
Nós identificamos um bug
Há um pequeno bug na aplicação polls para corrigirmos:
O método Question.was_published_recently() retorna True se a Question foi publicada dentro do último dia (o que está correto), mas também, se o campo pub_date da Question estiver no futuro o retorno também é ‘recente’ (o que é um equívoco).
Para checar se o bug realmente existe, usando o Admin crie uma enquete na qual a data encontra-se no futuro e verifique o método através do shell:
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> # create a Question instance with pub_date 30 days in the future
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> # was it published recently?
>>> future_question.was_published_recently()
True
Qualquer coisa no futuro não podem ser considerada recente, isto é claramente um erro.
Criar um teste para expor um bug.
O que nós fizemos no shell para testar o problema é exatamente o que podemos fazer em um teste automatizado, então vamos voltar para o teste automatizado.
Um lugar convencional para os testes da aplicação é o arquivo tests.py, o sistema de testes irá encontrar automaticamente todos os testes que estiverem em qualquer arquivo cujo o nome comece com test.
Coloque o seguinte código no arquivo polls/tests.py na aplicação polls:
from datetime import *
from django.utils import timezone
from django.test import TestCase
from django.urls import reverse
from .models import Question
def create_question(question_text, days):
"""
Create a question with the given 'question_text' and published the
given number of 'days' offset to now (negative for questions published
in the past, positive for questions that have yet to be published).
"""
time = timezone.now() + datetime.timedelta(days=days)
return Question.objects.create(question_text=question_text, pub_date=time)
O que fizemos foi criar uma subclasse django.test.TestCase com o método que cria uma instância de Question com pub_date no futuro. Nós então vamos checar a saída de was_published_recently() – que deve ser False.
EXECUTANDO O TESTE
No terminal, nós podemos executar nosso test:
python manage.py test polls
E você verá algo como:
Creating test database for alias ‘default’…
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
———————————————————————-
Traceback (most recent call last):
File “/path/to/mysite/polls/tests.py”, line 16, in test_was_published_recently_with_future_question
self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False
———————————————————————-
Ran 1 test in 0.001s
FAILED (failures=1)
Destroying test database for alias ‘default’…
O que ocorreu foi o seguinte:
- python manage.py test polls procurou por testes na aplicação polls
- ele encontrou uma subclass da classe django.test.TestCase
- ele cria um banco de dados especial com o propósito de teste
- ele procurou por métodos de test – aquele cujo nome começam com test
- em test_was_published_recently_with_future_question é criado uma instância de Question na qual o campo pub_date está 30 dias no futuro
- … e usando o método assertIs(), descobrimos que was_published_recently() retorna True, mas queremos que retorne False
O teste nos informa falhou e até mesmo a linha na qual a falha ocorreu.
CORRIGINDO O ERRO
Nós sabemos onde o problema está. “Question.was_published_recently()” deveria retornar “False” se “pub_date” está com a data no futuro. Refatore o método no “models.py“, e dessa forma ele só retornará “True” se a data também estiver no passado:
polls/models.py
def was_published_recently(self):
now = timezone.now()
return now - timedelta(days=1) <= self.pub_date <= now
Execute e teste novamente
$ python manage.py test polls
Saída:
Creating test database for alias ‘default’…
System check identified no issues (0 silenced).
.
———————————————————————-
Ran 1 test in 0.001s
OK
Destroying test database for alias ‘default’…
Depois de identificar um erro, nós escrevemos um teste que demonstra e corrige o erro no código, então o nosso teste passa.
Muitas outras coisas podem dar errado com a nossa aplicação no futuro, mas você pode ter certeza que não vamos reintroduzir este bug inadvertidamente, porque simplesmente rodando os testes já receberemos o aviso imediatamente.
Nós podemos considerar que esta pequena parte da aplicação está a salvo para sempre.
Depois de identificar um erro, nós escrevemos um teste que demonstra e corrige o erro no código, então o nosso teste passa.
Muitas outras coisas podem dar errado com a nossa aplicação no futuro, mas você pode ter certeza que não vamos reintroduzir este bug inadvertidamente, porque simplesmente rodando os testes já receberemos o aviso imediatamente.
Nós podemos considerar que esta pequena parte da aplicação está a salvo para sempre.
TESTES MAIS ABRANGENTES
Nós podemos nos aprofundar no método was_published_recently(). De fato, seria certamente embaraçoso introduzir um novo bug enquanto conserta outro.
Adicione mais dois métodos de teste na mesma classe, para testá-la melhor.
polls/tests.py
def test_was_published_recently_with_old_question(self):
"""
was_published_recently() returns False for questions whose pub_date
is older than 1 day.
"""
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
old_question = Question(pub_date=time)
self.assertIs(old_question.was_published_recently(), False)
def test_was_published_recently_with_recent_question(self):
"""
was_published_recently() returns True for questions whose pub_date
is within the last day.
"""
time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
recent_question = Question(pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)
E agora nós temos 3 testes que confirmam que Question.was_published_recently() retorna valores TRUE ou FALSE para Questions no passado, recente e futuro.
Rode novamente os testes:
python manage.py test polls
De novo, polls é uma simples aplicação, mas independente de quão complexa ela se torne no futuro e qualquer outro código que venha a interagir com ela, nós agora temos alguma garantia que o método que nós escrevemos com testes vai se comportar da maneira esperada.
Para baixar o código como está até agora, acesse o meu github no link abaixo:
https://github.com/toticavalcanti/django_course/tree/automated_tests
AULA 17
AULA 19
Todas as Aulas da App Polls
Página Principal
Obrigado
Até a próxima