使用Unittest测试简单主页

unsplash

如何进行单元测试

创建Django应用并编写第一个测试用例

执行命令 python manage.py startapp lists 创建一个叫lists的应用。

lists/tests.py 里输入第一个测试用例:

1
2
3
4
5
6
from django.test import TestCase

class SmokeTest(TestCase):

def test_bad_maths(self):
self.assertEqual(1 + 1, 3)

在命令行里执行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
9
from 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
2
3
4
from django.shortcuts import render

# Create your views here.
home_page = None

再次运行,报错为路由/未找到。


superlists/urls.py添加如下代码:

1
2
3
4
5
6
7
8
from django.contrib import admin
from django.conf.urls import url
from lists import views

urlpatterns = [
url(r'^$', views.home_page, name='home'),
url(r'^admin/', admin.site.urls),
]

此时单元测试结果如下,视图函数必须是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
5
from 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.pyHomePageTest类里添加第二个单元测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from 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.pyhome_page函数修改如下:

1
2
def home_page(request):
return HttpResponse()

再次测试,报错:

1
2
self.assertTrue(html.startswith('<html>'))
AssertionError: False is not true


修改lists/views.pyhome_page函数:

1
2
def home_page(request):
return HttpResponse('<html>')

再次测试,报错:

1
AssertionError: '<title>To-Do lists</title>' not found in '<html>'


修改lists/views.pyhome_page函数:

1
2
def home_page(request):
return HttpResponse('<html><title>To-Do lists</title>')

再次测试,报错:

1
2
self.assertTrue(html.endswith('</html>'))
AssertionError: False is not true


修改lists/views.pyhome_page函数:

1
2
def home_page(request):
return HttpResponse('<html><title>To-Do lists</title></html>')

再次测试,就OK了:

1
2
3
4
5
6
7
8
9
$ python manage.py test
Creating test database for alias 'default'...
..
---------------------------------------------------------------------
Ran 2 tests in 0.001s

OK
System check identified no issues (0 silenced).
Destroying test database for alias 'default'...

快速命令介绍

启动Django服务

Rpython manage.py runserver

进行功能测试

python functional_tests.py

Django运行单元测试

python manage.py test

单元测试流程(TDD)

  1. 运行单元测试
  2. 修改/编写代码
  3. 回到第一步

参考资料

0%