如何进行单元测试
创建Django应用并编写第一个测试用例
执行命令 python manage.py startapp lists
创建一个叫lists
的应用。
在lists/tests.py
里输入第一个测试用例:
1 | from django.test import TestCase |
在命令行里执行python manage.py test
,可能的结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17$ python manage.py test
Creating test database for alias 'default'...
F
======================================================================
FAIL: test_bad_maths (lists.tests.SmokeTest)
---------------------------------------------------------------------
Traceback (most recent call last):
File "...python-tdd-book/lists/tests.py", line 6, in test_bad_maths
self.assertEqual(1 + 1, 3)
AssertionError: 2 != 3
---------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
System check identified no issues (0 silenced).
Destroying test database for alias 'default'...
创建测试用例
接下来,考虑书写正式的测试用例。
测试视图函数和路由相匹配
修改lists/tests.py
内容如下,以测试跟路由/
是否和函数home_page
对应(虽然该函数现在还没写)1
2
3
4
5
6
7
8
9from django.urls import resolve
from django.test import TestCase
from lists.views import home_page
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
found = resolve('/')
self.assertEqual(found.func, home_page)
此时执行单元测试一定会失败,报错home_page
未定义。
在lists/views.py
里添加如下内容
1 | from django.shortcuts import render |
再次运行,报错为路由/
未找到。
在superlists/urls.py
添加如下代码:
1 | from django.contrib import admin |
此时单元测试结果如下,视图函数必须是callable
。1
2[...]
TypeError: view must be a callable or a list/tuple in the case of include().
修改lists/views.py
内容如下1
2
3
4
5from django.shortcuts import render
# Create your views here.
def home_page():
pass
运行单元测试,可以看到已经能通过了:1
2
3
4
5
6
7
8
9$ python manage.py test
Creating test database for alias 'default'...
.
---------------------------------------------------------------------
Ran 1 test in 0.003s
OK
System check identified no issues (0 silenced).
Destroying test database for alias 'default'...
测试路由的返回值
可以通过:
- 测试返回值是否以
<html>
标记开头 - 测试返回值是否以
</html>
标记结尾 - 测试返回值的
<title>
标记内容
在lists/tests.py
的HomePageTest
类里添加第二个单元测试:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21from django.urls import resolve
from django.test import TestCase
from django.http import HttpRequest
from lists.views import home_page
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
found = resolve('/')
self.assertEqual(found.func, home_page)
def test_home_page_returns_correct_html(self):
request = HttpRequest()
response = home_page(request)
html = response.content.decode('utf8')
self.assertTrue(html.startswith('<html>'))
self.assertIn('<title>To-Do lists</title>', html)
self.assertTrue(html.endswith('</html>'))
执行单元测试报错:TypeError: home_page() takes 0 positional arguments but 1 was given
将lists/views.py
的home_page
函数修改如下:1
2def home_page(request):
return HttpResponse()
再次测试,报错:1
2self.assertTrue(html.startswith('<html>'))
AssertionError: False is not true
修改lists/views.py
的home_page
函数:1
2def home_page(request):
return HttpResponse('<html>')
再次测试,报错:1
AssertionError: '<title>To-Do lists</title>' not found in '<html>'
修改lists/views.py
的home_page
函数:1
2def home_page(request):
return HttpResponse('<html><title>To-Do lists</title>')
再次测试,报错:1
2self.assertTrue(html.endswith('</html>'))
AssertionError: False is not true
修改lists/views.py
的home_page
函数:1
2def home_page(request):
return HttpResponse('<html><title>To-Do lists</title></html>')
再次测试,就OK了:
1 | $ python manage.py test |
快速命令介绍
启动Django服务
Rpython manage.py runserver
进行功能测试
python functional_tests.py
Django运行单元测试
python manage.py test
单元测试流程(TDD)
- 运行单元测试
- 修改/编写代码
- 回到第一步