unittest简介 unittest 是一个Python单元测试框架。它受到 JUnit 的启发,与其他语言中的主流单元测试框架有着相似的风格。其支持测试自动化,配置共享和关机代码测试。支持将测试样例聚合到测试集中,并将测试与报告框架独立。
主要参考 unittest - 单元测试框架 。
脚本编写 新建一个 tests/test_demo.py 脚本,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import unittestclass TestStringMethods (unittest.TestCase): def test_upper (self ): self.assertEqual('foo' .upper(), 'FOO' ) def test_isupper (self ): self.assertTrue('FOO' .isupper()) self.assertFalse('Foo' .isupper()) def test_split (self ): s = 'hello world' self.assertEqual(s.split(), ['hello' , 'world' ]) with self.assertRaises(TypeError): s.split(2 ) if __name__ == '__main__' : unittest.main()
继承 unittest.TestCase 就创建了一个测试样例。上述三个独立的测试是三个类的方法,这些方法的命名都以 test 开头。 这个命名约定告诉测试运行者类的哪些方法表示测试。
每个测试的关键是:调用 assertEqual() 来检查预期的输出; 调用 assertTrue() 或 assertFalse() 来验证一个条件;调用 assertRaises() 来验证抛出了一个特定的异常。
通过 setUp() 和 tearDown() 方法,可以设置测试开始前与完成后需要执行的指令。
最后的代码块中,演示了运行测试的一个简单的方法。 unittest.main() 提供了一个测试脚本的命令行接口。
执行测试 方法一:脚本级别调用(直接运行脚本)
1 2 3 python tests/test_demo.py python tests/test_demo.py -v python -m unittest tests/test_demo.py
方法二:包、模块、类和方法级别调用
1 2 3 4 5 6 7 8 # 包级别调用(进入tests目录查找所有test_*.py文件并运行) python -m unittest discover -s tests -p "test_*.py" # 模块级别调用 python -m unittest tests.test_demo # 类级别调用 python -m unittest tests.test_demo.TestStringMethods # 方法级别调用 python -m unittest tests.test_demo.TestStringMethods.test_upper
单元测试之mock 单元测试时,如果涉及网络请求,建议使用mock模块来模拟。
1 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import jsonimport unittestfrom unittest import mockimport requestsdef request_system (method: str , url: str , data={} ): headers = { 'Content-Type' : 'application/json' } response = requests.request(method=method, url=url, headers=headers, data=json.dumps(data)) return response def login (username: str , password: str ): LOGIN_URL='http://127.0.0.1/login' data = { 'username' : username, 'password' : password } response = request_system('POST' , LOGIN_URL) if response.status == 200 : return json.loads(response.text) else : return None class TestMockMethods (unittest.TestCase): def test_request_system (self ): mock_response = mock.Mock() mock_response.status_code = 200 mock_response.text = json.dumps({"code" : 0 , "msg" :"success" }) request_system = mock.Mock(return_value=mock_response) response = request_system(method='POST' ,url='http://127.0.0.1/' ) print (response.status_code) print (response.text) self.assertEqual(200 , response.status_code) def test_login (self ): login = mock.Mock(return_value={"code" : 0 , "msg" :"success" }) data = login(username='voidking' ,password='voidking' ) print (data) self.assertEqual(0 , data.get('code' )) if __name__ == '__main__' : unittest.main()
这种模拟测试方式很巧妙,适合测试访问第三方接口,但是并不会真正发出请求。 另一个问题来了,Python怎么测试自己的接口?不知道。 想到以前使用Beego框架进行开发,它的单元测试就很巧妙,先在测试数据库插入数据,然后通过beego.BeeApp.Handlers.ServeHTTP(w, r)把自己临时启动起来,最后自己的单元测试调用自己的接口。 其中的关键在于把自己启动起来,理论上Python也能做到。