Aula 18 – Testes automatizados – Escrevendo nosso primeiro teste

Criando uma primeira aplicação com Django e mysql

Testes automatizados 02

https://docs.djangoproject.com/pt-br/1.11/intro/tutorial05/

Testes automatizados

Testes automatizados – test-driven development

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

Obrigado

Até a próxima

 

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *