个人学习笔记,参考django官方文档:https://docs.djangoproject.com/zh-hans/3.2/ 本文同步发表在我的个人博客上:https://sunguoqi.com/2021/12/10/Django_02/
一、自动化测试
??测试代码,就是检查你的代码能否正常运行(废话)
??实话说,就目前为止,我写程序都是运行——>报错——>然后看报错信息——>print 输入输出这样去测试的。但是项目毕竟是一个整体的项目,这样测试未免太不专业了。
??自动化测试具有以下优点:
- 测试将节约你的时间
- 测试不仅能发现错误,而且能预防错误
- 测试是你的代码更有吸引力
- 测试有利于团队协作
听起来不错,那就试试吧!
1、首先得有个 BUG
??按照我们之前写的这个应用逻辑,当我们访问index 这个页面时,我们应该会得到最近发布的五条投票,如果有五条的话。
??但是现在有一个小 bug 就是,如果我们的投票是定时到明天发布的,我们的想法是用户明天才能看到这条投票,index 页面不应该显示这条数据,但按照目前的逻辑,index 会立马显示这条数据。
??注意 :上面描述的确实是一个 BUG,但是还有一个重要的 BUG,就是之前我们再写数据模型时,我们根本没定义任何方法来显示一天内的数据。原谅我没有看到这个要求:Question 是在一天之内发布的。
下面是 model 层现在的状态。
from django.db import models
import datetime
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
2、暴露这个 BUG
??文字描述这个 BUG 确实有点苍白无力,下面我们用 python manage.pyshell 命令来暴露这个 BUG。
??在项目根目录下打开终端,输入python manage.py shell 进入交互式编译环境。
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> # 创建了一个实例对象,他的时间是未来的。
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> # 会公开近期投票吗?
>>> future_question.was_published_recently()
True
??很显然现在应用会公开未来的投票,所以我们要修复这个 BUG,哦对了,这不是一个自动化测试,我们只是在交互式环境下测试的,我们应该把他写成一个文件,当项目运行时,执行自动化测试。
3、自动化测试
??按照惯例,Django 应用的测试应该写在应用的 tests.py 文件里。测试系统会自动的在所有以 tests 开头的文件里寻找并执行测试代码。
polls/tests.py
from django.test import TestCase
import datetime
from django.utils import timezone
from .models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
"""
未来的一个时间他的返回值应该是False
"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
4、运行测试
??在终端执行测试命令python manage.py test polls
PS J:\study_django\mysite> python manage.py test polls
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E
======================================================================
ERROR: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
未来的一个时间他的返回值应该是False
----------------------------------------------------------------------
Traceback (most recent call last):
File "J:\study_django\mysite\polls\tests.py", line 19, in test_was_published_recently_with_future_question
self.assertIs(future_question.was_published_recently(), False)
AttributeError: 'Question' object has no attribute 'was_published_recently'
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (errors=1)
Destroying test database for alias 'default'...
PS J:\study_django\mysite>
??以下是自动化测试的运行过程:
-
python manage.py test polls 将会寻找 polls 应用里的测试代码 -
它找到了 django.test.TestCase 的一个子类 -
它创建一个特殊的数据库供测试使用 -
它在类中寻找测试方法——以 test 开头的方法。 -
在 test_was_published_recently_with_future_question 方法中,它创建了一个 pub_date 值为 30 天后的 Question 实例。 -
接着使用 assertls() 方法,发现 was_published_recently() 返回了 True ,而我们期望它返回 False 。
5、修复这个 BUG
??当 pub_date 为未来某天时, Question.was_published_recently() 应该返回 False 。修改 models.py 里的方法,让它只在日期是过去式的时候才返回 True :
polls/models.py
...
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
...
6、更全面的测试
??最好对过去、最近、将来都进行测试。于是把测试代码修改如下。
from django.test import TestCase
import datetime
from django.utils import timezone
from .models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
"""
未来的一个时间他的返回值应该是False
"""
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
def test_was_published_recently_with_old_question(self):
"""
最近一天的
"""
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):
"""
过去的
"""
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)
7、其他方案
??还有一个解决思路就是,我们不应该显示未来的投票,那么我们在视图显示时,就应该过滤掉过去 和未来 这个我没有继续研究。
二、静态文件的引入
??首先,在 polls 目录下创建一个名为 static 的目录。Django 将在该目录下查找静态文件,这种方式和 Diango 在 polls/templates/ 目录下查找 template 的方式类似。
1、新建 css 样式
在静态文件目录下新建样式。
static/style.css
li a {
color: green;
}
2、引入静态文件
在模板中引入静态文件。
index.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'style.css' %}" />
3、运行项目
|