Lista más común de asserts:
link: https://docs.python.org/3/library/unittest.html#assert-methods
Bienvenida
Continuamos tu aprendizaje de Django
Testing
¿Qué son los tests?
Escribiendo nuestro primer test
Solucionando el error encontrado
Testing de Views
Creando más tests para IndexView
Ajustando detalles en los tests para IndexView
Creando tests para DetailView
Static Files
Agregando estilos a nuestro proyecto
Añadiendo una imagen de fondo
Django Admin
Mejorando el Admin: Questions
Mejorando el Admin: Change List
Bonus: ajustes finales
Comenzando a crear un Frontend
Añadiendo estilos al home de nuestra aplicación
Creando la estructura de la vista de detalle
Finalizando los estilos de la vista de detalle
Conclusiones
Conclusiones
Crea una cuenta o inicia sesión
¡Continúa aprendiendo sin ningún costo! Únete y comienza a potenciar tu carrera
Aportes 41
Preguntas 6
Lista más común de asserts:
link: https://docs.python.org/3/library/unittest.html#assert-methods
Mi aporte al reto:
Mi solución
def test_questions_with_future_pub_date(self):
"""
Questions with a pub_date greater than the current date should not appear in the Index View.
"""
Question(question_text='Present Question', pub_date=timezone.now()).save()
Question(question_text='Future Question', pub_date=timezone.now() + datetime.timedelta(days=30)).save()
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Present Question")
self.assertNotContains(response, "Future Question")
Solución al Challenge (atento a la retroalimentación)
def test_questions_with_future_pub_date(self):
"""Questions with date greater to timezone.now shouldn't be displayed"""
time = timezone.now() + datetime.timedelta(days = 30)
future_question = Question(question_text = "This is a Question for the test", pub_date = time)
future_question.save()
response = self.client.get(reverse('polls:index'))
self.assertNotIn(future_question, response.context['latest_question_list'])
(venv) [email protected]:~/work/premiosplatziapp # python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.....
----------------------------------------------------------------------
Ran 5 tests in 0.018s
OK
Destroying test database for alias 'default'...
Para evitar el error de los paréntesis que tuvo Facundo, les recomiendo instalar la extensión de VSCode llamado “Rainbow Brackets”. Es muy útil ya que identifica cada par de paréntesis con un color diferente y resalta que paréntesis le corresponde a su par.
Mi solución al reto luce de la siguiente manera (estaré atento a sus criticas constructivas xd):
Una ejercicio para hacer testing de una view es por ejemplo revisar si hay o no preguntas. Para esto, se crea una clase que testea a las vistas y al modelo y luego se crea un método para el caso específico:
En el archivo tests.py
class QuestionIndexViewTest(TestCase):
def test_no_questions(self):
"""If no question exist, an appropiate message is displayed"""
# estoy haciendo una peticion get http y se guarda en response
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context["latest_question_list"], [])
Si te aparece el siguiente error al ejecutar el test :
name ‘reverse’ is not defined
debes de importar el modulo reverse de Django
from django.urls import reverse
def test_IndexView_show_future_questions(self):
'''
IndexView shouldn't show questions that were posted in the future
'''
Question.objects.create(question_text='Question_now', pub_date=timezone.now())
Question.objects.create(question_text='Question_future', pub_date=timezone.now() + datetime.timedelta(days=30))
Question.objects.create(question_text='Question_past', pub_date=timezone.now() - datetime.timedelta(days=30))
path = reverse('polls:index')
response = self.client.get(path)
question_list = response.context['latest_question_list']
time_now = timezone.now()
for question in question_list:
print(question.question_text)
self.assertIs(question.pub_date>time_now, False)
Les comparto el código que realice para validar que no se esten mostrando preguntas futuras.
Si alguien tiene el mismo problema que yo con la view index y estan utilizando funciones view pueden aplicar el filtro de esta manera
def index(request):
latest_question_list = Question.objects.all().filter(pub_date__lte=timezone.now()).order_by("-pub_date")[:5]
return render(request,"polls/index.html",{
"latest_question_list":latest_question_list
})
El “assertContains” le podemos tirar alta magia.
Suponiendo que tenemos un texto adentro del index que dice :
“No polls here in this page. If you are here there is a problem .”
Le metemos en el assertContain solo un pedacito del texto FUNIONA.
y ademas
Se puede hacer comparativas in situ. Vean el codigo.
Por lo tanto ojo que si le metemos un mini string por ejemplo “tal” va a dar True si hay escrito “el tarro de talco” , " el SR. dijo tal cosa" , “el talisman del heroe” etc etc
Saludos
class QuestionIndexViewTest(TestCase):
def test_no_questions(self):
"""If no question existe, a raisonable message is displayed"""
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls here in" and "f you are here there is a probl")
def test_future_question_no_published(self):
"""If question pub date is in the future, don't show it in the index page"""
response = self.client.get(reverse("polls:index"))
time = timezone.now() + datetime.timedelta(days=15)
future_question = Question(question_text="Who is the best Platzi's Course Director ?", pub_date=time)
self.assertNotContains(response, future_question)
def test_questions_published_in_future_dont_be_displayed_in_present(self):
"""if a question have a pub_date in future, don´t be displayed now"""
time = timezone.now() + datetime.timedelta(days=30)
Question(question_text="¿Test Question?",pub_date=time).save()
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, "¿Test Question?")
Mi solución para el reto:
def test_no_future_question_are_displayed(self):
"""If there are a question published in the future, this question won't be displayed"""
response = self.client.get(reverse("polls:index"))
time = timezone.now() + datetime.timedelta(days = 30)
self.assertEqual(response.status_code, 200)
future_question = Question(question_text="¿Mejor página de Platzi?", pub_date=time)
self.assertNotContains(response, future_question.question_text)
Las pruebas que requieren una base de datos (conocidas como pruebas de modelo) no utilizarán tu base de datos “real” (de producción). Se crearán bases de datos separadas y vacías para las pruebas. Sin importar si las pruebas pasan o fallan, las bases de datos de prueba se destruirán cuando se hayan ejecutado todas las pruebas. Por este mismo motivo es valido esperar en la función test_no_questions() un response con el texto “No polls are available”.
Si viste los comentarios y te diste cuenta del comando assertNotIn y dijiste “donde has estado toda mi vida” dale like jajaja xD
Se agregan dos preguntas, una con fecha en el futuro y la otra con fecha de 300 minutos antes desde el momento de ejecución.
Se evalúa que las preguntas obtenidas en el contexto
estén en una fecha pub_date inferior o igual al momento de ejecución.
Si la pregunta futura viene en la respuesta lanza una excepción de error, ya que la validación es False.
def test_future_questions(self):
"""If future question is returned the test value is false"""
time_future = timezone.now() + datetime.timedelta(days=300)
future_question = Question(question_text="¿pregunta en el futuro?", pub_date=time_future)
now_question = Question(question_text="¿Pregunta ahora?", pub_date=timezone.now() - datetime.timedelta(minutes=300))
future_question.save()
now_question.save()
response = self.client.get(reverse("polls:index"))
for question in response.context["lates_question_list"]:
self.assertTrue(question.pub_date <= timezone.now())
Mi aporte a el reto:
def test_no_questions_future(self):
"""
If no question future exists, an appropiate message is displayed
"""
response = self.client.get(reverse("polls:index"))
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(question_text="¿Cuál es el mejor profesor de Platzi?", pub_date=time)
self.assertNotIn(future_question, response.context["latest_question_list"])
Uso el assertNotIn porque lo que haces es que a no está en b osea que la pregunta a futuro no se encuentre en la lista de las últimas preguntas
Mi codigo
Yo no tuve esa opción de ponerle un datetime a la pregunta cuando la añadí por Admin debido a “auto_now_add=True” que había puesto en el modelo Question para evitar esos errores y no modificar las preguntas. Les recomiendo revisar su código si de casualidad la consola de admin tiene algo similar.
Comparto mi solución:
def tets_no_questions_future(self):
"""test para validar que no existan preguntas del futuro"""
response = self.client.get(reverse("polls:index"))
preguntas_publicadas = Question.objects.exclude(pub_date__gte=datetime.date.today())
self.assertQuerysetEqual(response.context["latest_question_list"], preguntas_publicadas)
Hola el reto creo quedaría así :
def test_show_question_of_future(self):
"""If a question from future is show returns False"""
time_in_future = timezone.now() + datetime.timedelta(days=30)
question_from_future = Question(question_text="Question from the future?", pub_date=time_in_future)
question_from_future.save()
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, "Question from the future?")
Espero pueda servir a alguien
Mi solución es la siguiente.: Se agrega solo un registro con fecha del futuro, en la base de datos solo existiría un registro, pero está en el futuro el set de objetos debe venir vació.
``
def test_no_questions_future(self):
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(1,"¿Quién es el mejor Course Director de Platzi?",pub_date=time)
future_question.save()
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code,200)
#self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context["latest_question_list"],[])
```
```
Mi propuesta:
import datetime
from django.test import TestCase
from django.utils import timezone
from django.urls import reverse
from .models import Question
# * Lo más común es hacer tests sobre modelos y/o vistas en Django
class QuestionModelTests(TestCase):
def setUp(self):
self.question = Question(
question_text='¿Quién es el mejor Course Director de Platzi?')
self.future_time = timezone.now() + datetime.timedelta(days=30)
self.past_time = timezone.now() - datetime.timedelta(days=30)
self.recent_time = timezone.now()
def test_was_published_recently_with_future_questions(self):
"""was_published_recently returns False for questions whose pub_date is in the future"""
self.question.pub_date = self.future_time
self.assertIs(self.question.was_published_recently(), False)
def test_was_published_recently_with_past_questions(self):
"""was_published_recently returns True for questions whose pub_date is in the past"""
self.question.pub_date = self.past_time
self.assertIs(self.question.was_published_recently(), False)
def test_was_published_recently_with_recent_questions(self):
"""was_published_recently returns True for questions whose pub_date is today"""
self.question.pub_date = self.recent_time
self.assertIs(self.question.was_published_recently(), True)
class QuestionIndexViewTests(QuestionModelTests, TestCase):
def test_no_questions(self):
"""If no question exist, an appropiate message is displayed"""
# * Hago una petición GET al index de polls y guardo la respuesta en response
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
def test_show_only_recent_questions(self):
"""The view should only show recent questions. It cannot show future questions from the date they are consulted."""
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
future_question = [self.question, self.future_time]
self.assertNotContains(response, future_question)
Este es el test del reto;
def test_future_question(self):
"""
If a future question exist, isn't displayed on the index page.
"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(question_text="¿Quién es el mejor Course Director de Platzi?", pub_date=time)
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertQuerysetEqual(response.context["latest_question_list"], [])
Hola, yo realicé las siguientes pruebas:
class QuestionIndexViewTests(TestCase):
def test_no_question(self):
"""
If no questions exist, an appropriate message is displayed.
"""
response = self.client.get(reverse(('polls:index')))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['lastest_question_list'], [])
def test_no_question_with_future_question(self):
"""
Even if no questions exist, if a future question exists, an appropriate message is displayed.
"""
Question.objects.create(question_text="Future question.", pub_date = timezone.now() + datetime.timedelta(days=30))
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['lastest_question_list'], [])
def test_question_with_past_question_and_future(self):
"""
If even a past question exists, Only display the past question.
"""
Question.objects.create(question_text="Past question.", pub_date = timezone.now() - datetime.timedelta(days=30))
Question.objects.create(question_text="Future question.", pub_date = timezone.now() + datetime.timedelta(days=30))
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Past question.")
self.assertNotContains(response, "Future question.")
self.assertEqual(response.context['lastest_question_list'].count(), 1)
def test_question_with_past_and_actual_question(self):
"""
Exist only past and actual question. Show all questions.
"""
Question.objects.create(question_text="Past question.", pub_date = timezone.now() - datetime.timedelta(days=30))
Question.objects.create(question_text="Actual question.", pub_date = timezone.now())
response = self.client.get(reverse('polls:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Past question.")
self.assertContains(response, "Actual question.")
self.assertEqual(response.context['lastest_question_list'].count(), 2)
Espero que mi aporte le sirva a alguno. A estas alturas entre confundido y dandole duro al ejercio y con un poco de ayuda de github copilot les dejo la solucion al reto de la clase
.
Si estan como yo, un poco aturdidos por las nuevas funciones e informacion de django, algo que me ayudo mucho fue entrar al shell de django y desde alli empezar a ejecutar las funciones una a una para ver los inputs y las salidas, asi entendi un poco mejor la funcion reverse() por ejemplo
.
Ahora si la solucion al reto.
Primero toca colocar
from django.urls import reverse
cree en test.py
una funcion que devuleve un 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)
y luego implemente en class QuestionIndexViewTests(TestCase):
el siguiente metodo o test.
def test_future_question(self):
"""
Questions with a pub_date in the future aren't displayed on
the index page.
"""
create_question(question_text="Future question.", days=30)
response = self.client.get(reverse('polls:index'))
self.assertContains(response, "No polls are available.")
self.assertQuerysetEqual(response.context['latest_question_list'], [])
al correr los tests con:
py manage.py test polls
la salida fue:
Found 5 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.....
----------------------------------------------------------------------
Ran 5 tests in 0.024s
OK
Destroying test database for alias 'default'...
Si quieren correr los test usando Pychar Community, les dejo la configuarion
Mi Test queda así
def test_no_questions_in_the_future(self):
"""Question created in the future has not been included in latest_question_list"""
Question(question_text="Question in the future?", pub_date=timezone.now() + timezone.timedelta(days=1)).save()
response = self.client.get(reverse("polls:index"))
self.assertQuerysetEqual(response.context["latest_question_list"], [])
Mi propuesta: al ser una pregunta futura, no debería estar dentro del “latest_question_list”, que luego se representa en el index view 😃
def test_future_question_is_not_displayed(self):
""""If there is a future question, it is not shown in the index view"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(question_text="Quién es el mejor CD de Platzi?", pub_date=time).save()
response = self.client.get(reverse("polls:index"))
self.assertQuerysetEqual(response.context["latest_question_list"], [])
En la documentación no encontré nada que ayudase 😦
**Soluciob al reto de la clase anterior. **
Utilize el metodo assertEqual como lo recomendo el profe
def test_was_pusblished_recentely_with_present_question(self):
"""Was_published_recently returns True for quiestion whose pub_date is at now"""
time = timezone.now()
now_question = Question(question_text='¿Cual es el mejor estudiante de platzi?', pub_date= time)
self.assertEqual(now_question.was_published_recentely(), True)
def test_was_published_recentely_with_past_question(self):
"""Was_published_recently returns False for question Whose pub_date is in Past"""
time = timezone.now() - datetime.timedelta(days=1)
past_question = Question(question_text= '¿Cual es la mejor escuela de platzi?', pub_date= time)
self.assertAlmostEqual(past_question.was_published_recentely(), False)
Aquí va mi reto ;D
Esto de los tests es buenisimo, pero me gustaría saber si es posible debbugear los tests en VS Code para ver el flujo de la inofrmación.
Saludos.
Muy generalista, se pueden dividir los tests para ser mas especificos. Como hacer assertEqual en la longitud, assert de la pregunta esperada, etc.
Supongo que lo veremos en breve 😃
def test_future_question(self):
"""if the new question is in a future, dont let to see sach question"""
time = timezone.now() + timezone.timedelta(days=30)
future_question = Question.objects.create(question_text="future question",pub_date=time)
response = self.client.get(reverse("polls:index"))
self.assertNotContains(response,future_question)
Dejo las que hice
En Test
def test_get_queryset_with_future_questions(self):
"""If question.pub_date is in the future, it is not displayed"""
time = timezone.now() + dt.timedelta(days = 30)
future_question = Question(question_text = "Any Question", pub_date = time)
future_question.save()
response = self.client.get(reverse('polls:index'))
self.assertNotIn(future_question, response.context['latest_question_list'])
def test_get_queryset_with_old_questions(self):
"""If question.pub_date is older than 1 day, it is not displayed"""
time = timezone.now() - dt.timedelta(days = 1, seconds = 1)
old_question = Question(question_text = "Any Question", pub_date = time)
old_question.save()
response = self.client.get(reverse('polls:index'))
self.assertNotIn(old_question, response.context['latest_question_list'])
En views
def get_queryset(self):
"""Return the last five published questions."""
# return Question.objects.order_by("-pub_date")[:5]
# return Question.objects.filter(pub_date__lte = timezone.now()).order_by('-pub_date')[:5]
questions = Question.objects.filter(pub_date__lte = timezone.now())
questions = questions.filter(pub_date__gt = timezone.now() - dt.timedelta(days = 1))
questions = questions.order_by('-pub_date')[:5]
return questions
Comparto mis testCases
import datetime
from django.test import TestCase
from django.utils import timezone
from .models import Question
class QuestionModelTests(TestCase):
SAMPLE_QUESTION = "¿Is this a question?"
def test_was_published_recently_with_future_questions(self):
"""Was published recently should return False for questions whose
pub_date is in the future."""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(question_text=self.SAMPLE_QUESTION, pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
def test_was_not_published_recently(self):
"""Was published recently should return False for questions whose
pub_date is older than 1 day."""
time = timezone.now() - datetime.timedelta(days=1, seconds=1)
old_question = Question(question_text=self.SAMPLE_QUESTION, pub_date=time)
self.assertIs(old_question.was_published_recently(), False)
def test_was_published_recently_with_recent_question(self):
"""Was published recently should return 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(question_text=self.SAMPLE_QUESTION, pub_date=time)
self.assertIs(recent_question.was_published_recently(), True)
Hola profe, tengo un error en la linea:
self.assertContains(response, “No Polls are available”)
En la consola: AssertionError: False is not true : Couldn’t find ‘No Polls are available’ in response
He revisado el codigo mil veces, es igualito al tuyo. Si comento la linea, el test funciona. Ayuda porfa!!
Yo hice 2 pruebas.
Una con un solo registro en el futuro.
La segunda con 2 registros uno en el futuro y otro en el presente
class QuestionIndexViewTest(TestCase):
def test_no_questions(self):
""" If no question exits, an appropiate message is displayed"""
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No Polls are avariable.")
self.assertQuerysetEqual(response.context["latest_question_list"], [])
def test_was_no_publish_questions_in_the_future(self):
"""If there is a publication that has a date in the future, it should not be published. and send the message: No Polls are avariable."""
time = timezone.now() + datetime.timedelta(days=30)
Question( question_text="¿Quien es el mejor Course Director de Platzi?", pub_date = time ).save()
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "No Polls are avariable.")
self.assertQuerysetEqual(response.context["latest_question_list"], [])
def test_was_no_publish_questions_in_the_future_and_publish_question_now(self):
"""If there is a publication that has the future date and today's publications, only those of today should be published. """
time = timezone.now() + datetime.timedelta(days=30)
Question( question_text="¿Quien es el mejor Course Director de Platzi?", pub_date = time ).save()
Question( question_text="¿Cual es el mejor curso de Platzi?", pub_date = timezone.now() ).save()
response = self.client.get(reverse("polls:index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "¿Cual es el mejor curso de Platzi?")
self.assertEqual(len(response.context["latest_question_list"]), 1)
Yo hice esta (para los 30 días después), pero quería hacer (la de un día en concreto).
tests
def test_was_published_last_time(self):
"""
was_published_last_time returns True for questions whose pub_date is in the past time
"""
time = timezone.now() - datetime.timedelta(days=30)
last_question = Question(question_text="¿Quién es el mejor Course Director de Platzi?", pub_date=time)
# Verificar que el resultado de aplicar el método was_published_last_time() sobre last_question es igual a verdad
self.assertIs(last_question.was_published_last_time(), True)
models
def was_published_last_time(self):
return self.pub_date <= timezone.now() -datetime.timedelta(days=30)
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?
o inicia sesión.