前言
单元测试是软件开发中不可或缺的一部分,可以帮助开发人员确保代码的正确性、可靠性和稳定性,python是一种广泛使用的程序语言,提供了多种单元测试工具,最常用的是unittest。本文将介绍unittest package, 包括如何编写测试TestCase、执行测试、断言以及使用测试套件TestSuite等,还将介绍测试覆盖率的概念,以及如何使用unittest来计算测试覆盖率
unittest
unittest是python自带的一个单元测试框架,可以帮助开发人员编写和执行单元测试,unittest框架提供了不少概念,包括断言、测试用例和测试套件等。unittest框架的核心是TestCase类,这个类用于定义单元测试,TestCase类中定义了许多测试方法
1 unittest框架最核心的4个概念
- TestCase:测试用例:一个testcase的实例就是一个测试用例
- TestSuite:测试套件:多个测试用例集合在一起,TestLoader:是用来加载TestCase到TestSuite中的
- TextTestRunner:测试运行程序:用来执行测试用例的
- fixture:测试环境搭建和销毁,测试前准备环境的搭建setUp,执行测试代码run,以及测试后环境的还原tearDown
unittest不仅能做单元测试、集成测试、系统测试,可以做web测试、接口测试、app测试
导入模块:
import unittest
pycharm设置:
简单例子
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_add(self):
self.assertEqual(add(1, 2), 3)
self.assertEqual(add(0, 0), 0)
if __name__ == '__main__':
unittest.main()
在示例中,定义了一个add函数,然后编写了一个测试类TestAdd继承了unittest.TestCase类,并定义了一个测试方法test_add,在这个测试方法中,使用了self.assertEqual断言来比较add函数的输出是否达到预期结果
2 使用unittest.TestCase定义测试项目
编写测试程序是单元测试中的一个关键步骤,测试程序是指对程序码的一个特定部分进行测试的一个单元,在python中,可以通过继承unittest.TestCase类来定义测试,如下例子:
程序码:检查是否登录成功
def login_check(username = None, password = None):
if 6 <= len(password):
if username =='python' and password == '123456':
return {"code":0, "msg":"登陆成功"}
else:
return {"code": 1, "msg": "账户或密码不正确"}
else:
return {"code": 1, "msg": "密码长度再6-1位之间"}
"""
1、账户、密码正确 ====》 {"code":0, "msg":"登陆成功"}
2、账号正确,密码再6-18之间 ====》 {"code": 1, "msg": "账户或密码不正确"}
3、账号正确,密码长度少于6 ====》 "code": 1, "msg": "密码长度再6-18位之间"
4、账号正确,密码长度对于18 ====》"code": 1, "msg": "密码长度再6-18位之间"
5、错误账号,密码正确 ===》{"code": 1, "msg": "账户或密码不正确"}
.....
"""
简单的范例:
#第一步建立一个类,一般Test开头代表测试类
#unittest框架自动设置好了实例,不用调实例就可以执行
class TestLogin(unittest.TestCase):
#测试用例的方法
def test_login_success(self):
"""登录成功用例"""
username = 'python'
password = '123456'
expected_response = {"code":0, "msg":"登陆成功"}
#调用被测试的单元,获得实际结果
actual_response = login_check(username, password)
#判断预期结果和实际结果是否存在某种关系,断言assert
#TODO:虽然断言有很多种方法一般使用assertTrue
#AssertionError
#self.assertEqual(expected_response,actual_response)
self.assertTrue(expected_response == actual_response)
#测试用例2
def test_login_error(self):
username = ''
password = ''
expected_response = {"code": 1, "msg": "账户或密码不正确"}
actual_response = login_check(username, password)
self.assertTrue(expected_response == actual_response)
在这个示例中,定义一个测试用例TestLogin,并定义了2个测试方法test_login_success、test_login_error,在这些测试方法中,使用断言来检查函数的输出是否符合预期,断言可以确保待测函数在不正确的参数下会引发异常,从而保证待测函数的正确性
3 使用unittest.main()执行测试
在编写测试程序后,需要执行这些测试项目,并确定待测函数的输出是否符合预期,在python中,可以通过unittest.main()来执行测试
如图例子:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('hello'.upper(), 'HELLO')
def test_isupper(self):
self.assertTrue('HELLO'.isupper())
self.assertFalse('Hello'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# 檢查s.split的結果是否為 ['hello', 'world']
with self.assertRaises(TypeError):
s.split(2)
# 檢查s.split(2)是否會引發TypeError異常
if __name__ == '__main__':
unittest.main()
在这个实例中,执行unittest.main(),会自动执行TestStringMethods类中的所有参数方法,如果加入verbosity参数来执行此测试,
if __name__ == '__main__':
unittest.main(verbosity=2)
unittest会提供详细的报告,报告中包含了每个测试的名称、状态等信息
4 断言 (assert)
断言是单元测试中的一个重要部分,用于检测待测还能输的输出是否符合预期,在python中,unittest框架提供了很多种断言方法,包括以下几种:
- assertEqual:检查两个值是否相等,如果不相等,则测试失败。
- assertNotEqual:检查两个值是否不相等,如果不相等,则测试失败。
- assertTrue:检查一个值是否为True,如果不是,则测试失败。
- assertFalse:检查一个值是否为False,如果不是,则测试失败。
- assertIs:检查两个值是否是同一个对象,如果不是,则测试失败。
- assertIsNot:检查两个值是否不是同一个对象,如果是,则测试失败。
- assertIn:检查一个值是否包含在另外一个值中,如果不是,则测试失败。
- assertNotIn:检查一个值是否不包含在另外一个值中,如果是,则测试失败。
- assertRaises:检查一个函数是否会引发异常,如果不会,则测试失败。
更多assert用法可以参考:Python unittest Assertions Cheat Sheet - Kapeli
例子:
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_add(self):
self.assertEqual(add(1, 2), 3)
self.assertNotEqual(add(0, 1), 0)
def test_add_negative(self):
self.assertEqual(add(-1, -2), -3)
self.assertNotEqual(add(-1, -1), 0)
if __name__ == '__main__':
unittest.main()
使用恰当的断言对待测试函数的输出进行验证可以提高测试的精度,从而更好发现和修复程序码中的错误