单元测试就是对单个模块或者是单个类或者是单个函数进行测试;一般是开发做的,按照测试阶段来分,一般是单元测试、集成测试、系统测试、验收测试。
2.为什么需要做单元测试?
1)单元测试之后,才是集成测试。单个单个功能模块测试通过之后,才能将单个功能模块集成起来做集成测试。为了从底层发现bug,减少模块合成之后出现的问题。
2)越早发现bug越好,这样可以早点发现问题,不然等问题积累到后面,如果做错了就要推倒重来,对于时间和经费来说,也是非常的浪费。
对于我们测试来说:我们就单元测试是为了执行测试用例的。
1.unittset框架最核心的四个概念:
- TestSuite:多个测试用例集合在一起。TestLoader:是用来把TestCase加载到TestSuite中的。
- TextTestRunner:用来执行测试用例的。
- fixture:测试用例环境的搭建和销毁,测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。
2.单元测试案例
def login_chek(username,password):
"""
登录校验的函数
:param username:账号
:param password:密码
:return:
""" if 6 <= len(password) <= 18: if username == 'python18' and password == 123456: return {'code':'0000','massage':'账户密码正确,登陆成功'} else: return {'code':'0001','massage':'账户或者密码不正确,登陆失败'} else: return {'code': '0001', 'massage': '密码长度必须在6-18位之间'}
-
设计用例测试上面的登陆校验是否正常?
1.TestCase类编写测试用例
继承unittest里面的TestCase类,继承这个类,写能写测试用例,每个测试用例我们都要记得引入fixture,做一些准备以及结束的工作。
编写测试用例步骤如下:
1)导入unittest模块、被测文件或者其中的类(import unittest)
2)创建一个测试类,并继承unittest.TestCase,继承父类(unittest.TestCase)的属性与方法。
3)重写setUp和tearDown方法(如果有初始化条件和结束条件)
4)定义测试函数、函数名以test开头。测试用例
import unittest from pack import login_check # 继承unittest的TestCase类 class LoginTest(unittest.TestCase): def setUp(self): print("执行每一条测试用例之前都会执行这个方法,可以使用该方法,做测试之前的环境准备工作") def tearDown(self): print("执行完每一条测试用例之后都会执行该方法,可以使用该方法来恢复环境") # 一个测试用例就是该类中的一个方法。测试用例的方法必须要以test开头 # 正常的测试用例(账号、密码正确,登录成功) def test_login(self): # 预期结果 excepted = {'code':'0000','massage':'账户密码正确,登陆成功'} # 传入参数 data = ('python18','123456') # 调用被测函数,传入参数(需要解包),获取实际结果 res = login_check(*data) try: self.assertEqual(excepted,res) # 通过实例对象(self)来调用assertEqual()方法 except AssertionError as e: print("该测试用例测试未通过") # 可通过异常捕获来获取 raise e # 此处需要使用raise主动抛出异常 else: print("该测试用例测试通过") # 异常用例(账户错误,密码正确) def test_username_error(self): excepted = {'code':'0001','massage':'账户或者密码不正确,登陆失败'} data = ('java','123456') res = login_check(*data) try: self.assertEqual(excepted,res) except AssertionError as e: print("该测试用例测试未通过") # 可通过异常捕获来获取 raise e # 此处需要使用raise主动抛出异常 else: print("该测试用例测试通过") # 异常用例(账户正确,密码在6-18位,密码错误) def test_password_error(self): excepted = {'code':'0001','massage':'账户或者密码不正确,登陆失败'} data = ('python','112233') res = login_check(*data) try: self.assertEqual(excepted,res) except AssertionError as e: print("该条测试用例测试未通过") raise e else: print("该条测试用例测试通过") # 异常用例(账户正确,密码少于6位) def test_password_lt6(self): excepted = {'code': '0001', 'massage': '密码长度必须在6-18位之间'} data = ('python','1238777') res = login_check(*data) try: self.assertEqual(excepted,res) except AssertionError as e: print("该条测试用例测试未通过") raise e else: print("该条测试用例测试通过") # 异常用例(账户正确,密码长度大于18位) def test_password_gt18(self): excepted = {'code': '0001', 'massage': '密码长度必须在6-18位之间'} data = ('python','12333444455534343441675') res = login_check(*data) try: self.assertEqual(excepted,res) except AssertionError as e: print("该条测试用例测试未通过") raise e else: print("该条测试用例测试通过")
1.TestSuite&TestLoader的使用
TestSuite:测试集,把所有测试用例都存进来。常用的方法如下:
unittest.TestSuite()
方法一:addTest() 添加一个测试用例
方法二:addTest([,,,,]) 添加多个测试用例 添加用例的方式都是一样的。
unittest.TsetLoader()
方法三:unittest.TestLoader.loadTestFromModule(模块名)不需要加引号(注意要导入模块)
方法四:unittest.TestLoaderTestsFromTestCase(测试类名)不需要加引号
2.总结和疑问
1.定义的测试类和测试套件写在不同的模块里,为什么?
2.为何引入测试集,方便批量进行单元测试。
import unittest from pack.python13 import LoginTest from pack import python13 # 创建一个测试集合 suite = unittest.TestSuite() # 添加测试用例 # 第一种 单个用例添加:接收的参数是测试用例的对象 suite.addTest(LoginTest('test_login')) suite.addTest(LoginTest('test_username_error')) suite.addTest(LoginTest('test_password_lt6')) # 第二种 一次添加多条测试用例 suite.addTests([LoginTest('test_login'),LoginTest('test_username_error'),LoginTest('test_password_lt6')]) # 第三种 一次添加一个测试用例类(类名不需要加引号) loader = unittest.TestLoader() suite.addTest(loader.loadTestsFromTestCase(LoginTest)) # 需要先将LoginTest类导进来 # 第四种 通过模块去添加 loader = unittest.TestLoader() suite.addTest(loader.loadTestsFromModule(python13)) # 运行测试集合 # 创建一个runner对象 runner = unittest.TextTestRunner() runner.run(suite) # 执行测试套件
检查 | |
---|---|
assertEqual(a,b) | a == b (判断两个值是否相等) |
assertNotEqual(a,b) | a != b (判断两个值是否不相等) |
assertTrue(x) | bool(x) is True (判断对象的布尔值x是否为True) |
assertFalse(x) | bool(x) is False (判断对象的布尔值x是否为False) |
assertIs(a,b) | a is b(判断a和b是否是同一对象) |
assertIsNot(a,b) | a is not b |
assertIn(a,b) | a in b |
assertNotIn(a,b) |
需要将 HTMLTestRunnerNew 测试报告模板文件复制至site-packages目录下。
1.TextTestRunner的用法
-
测试用例已经集合完毕,如何来执行测试用例?
需要用到TextTestRunner,执行测试集合,用到的是TextTestRunner(),用run方法。
#创建runner对象
runner = unittest.TextTestRunner()
#这里将传入测试集合进行执行
runner.run(suite)
- . 代表测试用例通过 一个点代表一个测试用例
- E 代表测试用例执行出错了
3.生成测试报告
# 新建一个register_report.py文件 import unittest from python.register_testcase import RegisterTest from HTMLTestRunnerNew import HTMLTestRunner # 创建一个测试集合 suite = unittest.TestSuite() # 将测试用例加载到测试集合 loader = unittest.TestLoader() suite.addTest(loader.loadTestsFromTestCase(RegisterTest)) # 1、执行测试(套件)集合,并生成文本格式的测试报告 with open("report.txt","w",encoding='utf-8') as f: # 报告内容过于鸡肋,几乎不用 runner = unittest.TextTestRunner(f) runner.run(suite) # 2、执行测试(套件)集合,并生成HTML格式的测试报告 with open('report.html','w') as f: runner = HTMLTestRunner(stream=f, # 需要写入的文件名 verbosity=2, # 写入的等级,2是最高级的,也是最详细的 title ='python_test_rerport', # 报告的名称 description='这是pytest单元测试的一份测试报告', # 报告的相关描述 tester='WL') # 测试者姓名 runner.run(suite)