从零开始写博客系统——单元测试
背景
验证自己写的代码,是一项基本功。我们必须要保证我们的代码运行逻辑没有问题,才能发布代码,因此在本文,我们学习如何测试我们的代码。
测试的类别
我们的后台代码可以使用单元测试和接口测试来覆盖。
所谓单元测试,就是直接测试我们的代码逻辑,而不需要启动服务。
而接口测试,则是把我们的服务启动后,调用接口检查接口的返回值是否符合预期。
我们这里测试的时候选用的是Python
默认的unittest
框架,这个框架用来做基础的测试已经足够了。
单元测试
具体的定义就请自己进行搜索。
我们需要测试的对象,其实就是两个类,一个是Article
,一个是Articles
。
首先我们来分析Article
类,这个类非常简单,就是一个结构的定义类,因此我们直需要测试这个结构初始化是没问题的,并且转换结构没有问题就行了。
我们新建一个文件夹叫test
,放置我们的测试用例,新建一个文件叫test_unit.py
,用于存放单元测试用例。
test_unit.py
import unittest
import article
class TestUnit(unittest.TestCase):
def test_article_struct(self):
a = article.Article(1, "title", "content", "author", "2019-01-01", "2019-02-01", "category", ["tag1", "tag2"])
self.assertEqual(a.id, 1)
self.assertEqual(a.title, "title")
self.assertEqual(a.content, "content")
self.assertEqual(a.author, "author")
self.assertEqual(a.created_time, "2019-01-01")
self.assertEqual(a.modified_time, "2019-02-01")
self.assertEqual(a.category, "category")
self.assertEqual(a.tag, ["tag1", "tag2"])
def test_article_to_dict(self):
a = article.Article(1, "title", "content", "author", "2019-01-01", "2019-02-01", "category", ["tag1", "tag2"])
a_dict = a.to_dict()
self.assertEqual(a_dict["id"], 1)
self.assertEqual(a_dict["title"], "title")
self.assertEqual(a_dict["content"], "content")
self.assertEqual(a_dict["author"], "author")
self.assertEqual(a_dict["created_time"], "2019-01-01")
self.assertEqual(a_dict["modified_time"], "2019-02-01")
self.assertEqual(a_dict["category"], "category")
self.assertEqual(a_dict["tag"], ["tag1", "tag2"])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
我们这里会测试两个方法:
- 整个
Article
类的初始化,经过这个代码段的测试,可以保证每个字段的赋值的正确性。 Article
类属性转换成字典结构的转换方法的测试,由于我们在内部逻辑转变的时候,会用到这个转变后的字典,因此我们要保证从类属性转换成字典属性的正确性。
新手同学对于上面的代码看起来很奇怪,甚至会觉得,有点不可理解,这个代码看起来毫无价值,有点像是一堆废话。事实上,越是基础代码的测试,越重要,尤其在大型项目和世纪的工作中,大部分项目时间紧迫,开发业务的时候就很难有时间来顾及这些基础点,但是这类基础点对于项目来说又是基础中的基础,一旦出现问题,将直接影响项目的上层。
比如我们博客系统,核心就是博客数据,而博客数据全部都是基于这个类来做后续的变换的。一旦这里的赋值和结构转换出现了问题,那么整个博客系统的上层展示就会异常。
我们运行这个类,unittest
框架属于Python
标准库,因此无需而外安装,即可直接运行。
在我们的项目根目录运行命令:
python -m unittest test.test_unit
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
2
3
4
5
6
可以看到,输出结果运行两条测试用例成功。我们也可以验证一下这个测试的结果是否准确,我们该一下代码
self.assertEqual(a.title, "title1")
把这个title
改成title1
,我们再重新运行测试用例
python -m unittest test.test_unit
F.
======================================================================
FAIL: test_article_struct (test.test_unit.TestUnit)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/www/Documents/code/blog/test/test_unit.py", line 9, in test_article_struct
self.assertEqual(a.title, "title1")
AssertionError: 'title' != 'title1'
- title
+ title1
? +
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (failures=1)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
可以看到,这个测试用例就发现了赋值不正确的问题。
我们也可以直接对单个测试用例进行执行,命令如下:
python -m unittest test.test_unit.TestUnit.test_article_struct
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
2
3
4
5
6
unittest
命令后的就是文件路径+类名+方法名。具体的细节可以参考unittest — Unit testing framework — Python 3.10.4 documentation。
Articles
类的方法就比较多了,但是我们的接口很多逻辑都是依赖Articles
的,因此这个类也需要仔细的进行测试。代码如下:
import unittest
import article
class TestUnit(unittest.TestCase):
...
def test_articles_struct(self):
aas = article.Articles()
self.assertEqual(aas.total, 2)
self.assertEqual(len(aas.articles), 2)
def test_add_article(self):
aas = article.Articles()
a = article.Article(3, "title", "content", "author", "2019-01-01", "2019-02-01", "category", ["tag1", "tag2"])
aas.append(a)
self.assertEqual(aas.total, 3)
self.assertEqual(len(aas.articles), 3)
def test_qry_by_id(self):
aas = article.Articles()
a1 = aas.get_by_id(1)
self.assertEqual(a1.id, 1)
def test_update_article(self):
aas = article.Articles()
a = article.Article(1, "title_update", "content_update", "author", "2019-01-01", "2019-02-01", "category", ["tag1", "tag2"])
aas.update_by_id(1, a)
ua = aas.get_by_id(1)
self.assertEqual(ua.title, "title_update")
self.assertEqual(ua.content, "content_update")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
运行整个测试类,就可以查看我们验证的内容了。
python -m unittest test.test_unit.TestUnit
......
----------------------------------------------------------------------
Ran 6 tests in 0.000s
OK
2
3
4
5
6
总结
本文我们使用了单元测试对我们自己的代码进行了测试。
如果自己没办法独立完成的,同样可以参考代码:代码浏览 - blog - 从零开始写一个博客系统 - svenweng (coding.net)
思考
我这里只写了部分功能的单元测试,对于这种基础类的测试务必要全,希望读者能够自行完成剩下功能的单元测试。