《Python web 开发 测试驱动方法》学习笔记
完整代码地址:https://github.com/a523/TDD_django
第一部分
怎么测试视图函数传入正确的值渲染模板?
from django.template.loader import render_to_string
render_to_string 函数可以渲染模板,然后拿它的返回值和视图函数的返回的HTML比较。
from django.http import HttpRequest
HttpRequest 可以构造request类
然后把这个request类做参数传给视图函数,如:
def test_home_page_can_save_a_POST_request(self):
request = HttpRequest()
request.method = "POST"
request.POST['item_text'] = 'A new list item'
response = home_page(request)
self.assertIn('A new list item', response.content.decode())
expected_html = render_to_string(
'home.html',
{'new_item_text': 'A new list item'}
)
self.assertEqual(response.content.decode(), expected_html)
Djano处理重定向
人们都说处理完POST请求后一定要重定向
from django.shortcuts import redirect, render
def home_page(request):
if request.method == 'POST':
pass # do some thing ...
return redirect('/') # 重定向
return render(request, 'home.html')
隔离测试,Django 提供一个类 LiveServerTestCase 做功能测试
这个类会自动创建一个测试数据库,并启动一个开放服务器,让功能测试在其中运行。
LiveServerTestCase必须使用manage.py,有Django的测试运行程序运行
用Django 客户端做单元测试
使用Django测试客户端一起测试视图、模板、和URL。
下面是书中的用法:
lists/test.py
from django.test import TestCase
class ListViewTest(TestCase):
def test_displays_all_items(self):
Item.objects.create(text='itemey 1')
Item.objects.create(text='itemey 2')
response = self.client.get('/lists/the-only-list-in-the-world/')
# 测试客户端是Django中TestCase类的一个属性
self.assertContains(response, 'itemey 1')
self.assertContains(response, 'itemey 2')
但是, django 官方文档中是这样一种用法。
捕获URL中的参数
urls.py
from django.conf.urls import url
urlpatterns = [
url(r'^(\d+)/$', 'lists.views.view_list', name='view_list'),
url(r'^(\d+)/add_item$', 'lists.views.add_item', name='add_item'),
url(r'^new$', 'lists.views.new_list', name='new_list'),
]
lists/views.py
def view_list(request, list_id):
[...]
测试Django传入模板的上下文
lists/tests.py
def test_pass_correct_list_to_template(self):
other_list = List.objects.create()
correct_list = List.objects.create()
response = self.client.get('/lists/%d/' % correct_list.id)
self.assertEqual(response.context['list'], correct_list)
# response.context 表示要传入render函数的上下文
# ———— Django 测试客户端把上下文附在response对象上,方便测试。
第二部分
使用bootstrap美化网站
- 下载 Bootstrap,把它放在 lists 应用中一个新文件夹 static 里:
$ wget -O bootstrap.zip https://github.com/twbs/bootstrap/releases/download/\
v3.1.0/bootstrap-3.1.0-dist.zip
$ unzip bootstrap.zip
$ mkdir lists/static
$ mv dist lists/static/bootstrap
$ rm bootstrap.zip
- 修改base.html模板
<!DOCTYPE html>
<html lang="en">
<head>
<title>To-Do lists</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/static/bootstap/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
[...]
主要是加入 第6行 <link行;
<meta name="viewport" 行是为了适配移动端
还可以使用Django的{% static %} 模板标签,这样做更符合 DRY 原则,也不用硬编码 URL;
base.html 改成如下:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>To-Do lists</title>
<meta name="viewport" content="width=device-with, initial-scale=1.0">
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet" media="screen">
<link href="{% static 'base.css' %}" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3 jumbotron">
<div class="text-center">
<h1>{% block header_text %}{% endblock %}</h1>
<form method="POST" action="{% block form_action %}{% endblock %}">
<input name="item_text" id="id_new_item" class="form-control input-lg" placeholder="Enter a to-do item">
{% csrf_token %}
</form>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
{% block table %}
{% endblock %}
</div>
</div>
</div>
</body>
</html>
555