首页 > 其他分享 >06-UnitTest框架

06-UnitTest框架

时间:2024-07-29 19:18:57浏览次数:9  
标签:06 框架 UnitTest self 测试 print import unittest def

DAY-09课堂笔记


UnitTest基本使用

UnitTest框架介绍

  • 框架

    什么是框架?
    1. 框架英文单词framework
    2. 为解决一类事情的功能集合
    
  • UnitTest框架

    是Python自带的一个单元测试框架
    - ⾃带的, 可以直接使⽤, 不需要单外安装
    - 测试⼈员 ⽤来做⾃动化测试, 作为⾃动化测试的执⾏框架, 即 管理和执⾏⽤例的
    
  • 为什么使用UnitTest框架?

    1. 能够组织多个用例去执行
    2. 提供丰富的断言方法
    3. 能够生成测试报告
    
  • UnitTest 核心要素(组成)

    1. TestCase 测试⽤例, 这个测试⽤例是 unittest 的组成部分,作⽤是 ⽤来书写真正的⽤例代码(脚本)
    
    2. Testsuite 测试套件, 作⽤是⽤来组装(打包)TestCase(测试⽤例) 的,即 可以将多个⽤例脚本⽂件 组装到⼀起
    
    3. TestRunner 测试执⾏(测试运⾏), 作⽤ 是⽤例执⾏TestSuite(测试套件)的
    
    4. TestLoader 测试加载, 是对 TestSuite(测试套件) 功能的补充, 作⽤是⽤来组装(打包) TestCase(测试⽤例) 的
    
    5. Fixture 测试夹具, 是⼀种代码结构, 书写 前置⽅法(执⾏⽤例之前的⽅法)代码 和后置⽅法(执⾏⽤例之后的⽅法) 代码 ,即 ⽤例执⾏顺序 前置 ---> ⽤例 ---> 后置
    

TestCase 测试⽤例

书写真正的⽤例代码(脚本)
单独⼀个测试⽤例 也是可以执⾏
  • 步骤:

    1. 导包 unittest
    2. 定义测试类, 需要继承 unittest.TestCase 类, 习惯性类名以 Test 开头
    3. 书写测试⽅法, 必须以 test 开头
    4. 执⾏
    
  • 注意事项

    1. 代码⽂件名字 要满⾜标识符的规则
    2. 代码⽂件名 不要使⽤中⽂
    
  • 代码

    # 1. 导包
    import unittest
    
    
    # 2. 定义测试类:新建 测试类 ;只要继承unittest.TestCase类,就是测试类
    class TestDemo(unittest.TestCase):
    
        # 3. 定义测试方法:测试方法名称命名必须以test开头
        def test_01(self):
            print("测试一")
    
        def test_02(self):
            print("测试二")
    
    # 4.执行
    # 4.1 在类名或者⽅法名后边右键运⾏
    # 4.1.1 在类名后边, 执⾏类中的所有的测试⽅法
    # 4.1.2 在⽅法名后边, 只执⾏当前的测试⽅法
    
    

TestSuite 测试套件 和 TextTestRunner 测试执⾏

TestSuite(测试套件)

将多条⽤例脚本集合在⼀起,就是套件, 即⽤来组装⽤例的
  • 步骤

    1. 导包 unittest
    2. 实例化套件对象 unittest.TestSuite()
    3. 添加⽤例⽅法
    

TextTestRunner 测试执⾏

⽤来执⾏套件对象
  • 步骤

    1. 导包 unittest
    2. 实例化 执⾏对象 unittest.TextTestRunner()
    3. 执⾏对象执⾏ 套件对象 执⾏对象.run(套件对象)
    

整体步骤

1. 导包 unittest
2. 实例化套件对象 unittest.TestSuite()
3. 添加⽤例⽅法
-  3.1 套件对象.addTest(测试类名('测试⽅法名'))
4. 实例化 执⾏对象 unittest.TextTestRunner()
5. 执⾏对象执⾏ 套件对象 执⾏对象.run(套件对象)
# 1. 导包 unittest
import unittest
from TestCase import TestDemo
from TestCase_01 import TestDemo01

# 2. 实例化套件对象 unittest.TestSuite()
suite = unittest.TestSuite()
# 3. 添加⽤例⽅法
# -  3.1 套件对象.addTest(测试类名('测试⽅法名'))
suite.addTest(TestDemo('test_01'))
suite.addTest(TestDemo('test_02'))
suite.addTest(TestDemo01('test_03'))
suite.addTest(TestDemo01('test_04'))

# -  3.2套件对象.addTest(unittest.makeSuite(测试类名)) # 在
不同的 Python 版本中,可能没有提示
suite.addTest(unittest.makeSuite(TestDemo1))
suite.addTest(unittest.makeSuite(TestDemo2))

#  - 3.3
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestDemo1))
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestDemo2))

# 4. 实例化 执⾏对象 unittest.TextTestRunner()

runner = unittest.TextTestRunner()
# 5. 执⾏对象执⾏ 套件对象 执⾏对象.run(套件对象)
runner.run(suite)

TestLoader 测试加载

作⽤和 TestSuite 作⽤⼀样,组装⽤例代码, 同样也需要使⽤TextTestRunner() 去执⾏

需要使用10 个⽤例脚本 makeSuite()

使用unittest.TestLoader,通过该类下面的discover()方法自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件。

步骤

1. 导包 unittest
2. 实例化加载对象并加载⽤例 ---> 得到的是 套件对象(最终返回的还是测试套件对象,运行测试套件还需要使用TestRunner)
3. 实例化执⾏对象并执⾏
import unittest

# 实例化加载对象并加载⽤例,得到套件对象
# suite = unittest.TestLoader().discover('⽤例所在的⽬录', '⽤例代码⽂件名*.py')
suite = unittest.TestLoader().discover("./", "hm_02*.py")

# runner=unittest.TextTestRunner()
# runner.run(suite)

unittest.TextTestRunner().run(suite)

练习

1.

1. 创建⼀个⽬录 case, 作⽤就是⽤来存放⽤例脚本,
2. 在这个⽬录中创建 5 个⽤例代码⽂件 , test_case1.py
...
3. 使⽤ TestLoader 去执⾏⽤例
-----
将来的代码 ⽤例都是单独的⽬录 中存放的
test_项⽬_模块_功能.py
import unittest

suite = unittest.TestLoader().discover('case', 'test_case*.py')

unittest.TextTestRunner().run(suite)

2.

1. 定义⼀个 tools 模块, 在这个模块中 定义 add 的⽅法,可
以对两个数字求和,返回求和结果
2. 书写⽤例, 对 add() 函数进⾏测试
1, 1, 2
1, 2, 3
3, 4, 7
4, 5, 9
-----
之前的测试⽅法,直接⼀个 print
这个案例中的 测试⽅法,调⽤ add 函数, 使⽤ if 判断,来判断
预期结果和实际结果是否相符
预期结果 2 3 7 9
实际结果 调⽤ add()
import unittest
from tools import add

class testadd(unittest.TestCase):
    def test1(self):
        """1,1,2"""
        print(f"测试数据为:{1},{1},{2}")
        if 2==add(1,1):
            print(f"测试数据为:{1},{1},{2}通过")
        else:
            print(f"测试数据为:{1},{1},{2}不通过")


    def test2(self):
        """1,2,3"""
        print(f"测试数据为:{1},{2},{3}")
        if 3==add(1,2):
            print(f"测试数据为:{1},{2},{3}通过")
        else:
            print(f"测试数据为:{1},{2},{3}不通过")


    def test3(self):
        """3,4,7"""
        print(f"测试数据为:{3},{4},{7}")
        if 3==add(1,2):
            print(f"测试数据为:{3},{4},{7}通过")
        else:
            print(f"测试数据为:{3},{4},{7}不通过")

    def test4(self):
        """4,5,9"""
        print(f"测试数据为:{4},{5},{9}")
        if 3==add(1,2):
            print(f"测试数据为:{4},{5},{9}通过")
        else:
            print(f"测试数据为:{4},{5},{9}不通过")

Fixture

代码结构, 在⽤例执⾏前后会⾃动执⾏的代码结构
tpshop 登录
1. 打开浏览器 (⼀次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码1,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码2,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码3,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
5. 关闭浏览器 (⼀次)

方法级别Fixture

在每个⽤例执⾏前后都会⾃动调⽤, ⽅法名是固定的
def setUp(self): # 前置
 # 每个⽤例执⾏之前都会⾃动调⽤
 pass


def tearDown(self): # 后置
 # 每个⽤例执⾏之后 都会⾃动调⽤
 pass
# ⽅法前置 ⽤例 ⽅法后置
# ⽅法前置 ⽤例 ⽅法后置

类级别Fixture

在类中所有的测试⽅法执⾏前后 会⾃动执⾏的代码, 只执⾏⼀次
# 类级别的 Fixture 需要写作类⽅法
@classmethod
def setUpClass(cls): # 类前置
 	pass


@classmethod
def tearDownClass(cls): # 后置
 	pass
# 类前置 ⽅法前置 ⽤例 ⽅法后置 ⽅法前置 ⽤例 ⽅法后置类后置

模块级别Fixture(了解)

模块, 就是代码⽂件
模块级别 在这个代码⽂件执⾏前后执⾏⼀次
# 在类外部定义函数
def setUpModule():
     pass
    
    
def tearDownModule():
     pass
实现:
tpshop 登录
1. 打开浏览器 (⼀次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码1,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码2,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码3,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
5. 关闭浏览器 (⼀次)
import unittest


class TestLogin(unittest.TestCase):

    @classmethod
    def setUpClass(cls) -> None:
        print("1.打开浏览器")

    def setUp(self) -> None:
        print("2.打开⽹⻚, 点击登录")

    def test1(self):
        print('3. 输⼊⽤户名密码验证码1,点击登录 ')

    def test2(self):
        print('3. 输⼊⽤户名密码验证码1,点击登录 ')

    def test3(self):
        print('3. 输⼊⽤户名密码验证码1,点击登录 ')

    def tearDown(self) -> None:
        print("4.关闭网页")

    @classmethod
    def tearDownClass(cls) -> None:
        print("5.关闭浏览器")

DAY-10课堂笔记


断言

使用代码自动的判断预期结果和实际结果是否相符

assertEqual(预期结果,实际结果)
- 判断预期结果和实际结果是否相等,如果相等, 用例通过,如果不相等,抛出异常, 用例不通过

assertIn(预期结果,实际结果)
- 判断预期结果是否包含在 实际结果中, 如果存在,用例通过, 如果不存在,抛出异常,用例不通过
import unittest
class TestAssert(unittest.TestCase):
	def test_equal_1(self):
		self.assertEqual(10, 10) # 用例通过
	def test_assert_2(self):
		self.assertEqual(10, 11) # 用例不通过
	def test_in(self):
        # self.assertIn('admin', '欢迎 admin 登录') # 包含 通过
        # self.assertIn('admin', '欢迎 adminnnnnnnn 登录') # 包含 通过
        # self.assertIn('admin', '欢迎 aaaaaadminnnnnnnn 登录') # 包含 通过
        # self.assertIn('admin', '欢迎 adddddmin 登录') # 不包含 不通过
		self.assertIn('admin', 'admin') # 包含 通过
import unittest

from hm_02_assert import TestAssert

suite = unittest.TestSuite()

suite.addTest(unittest.makeSuite(TestAssert))
unittest.TextTestRunner().run(suite)

参数化

- 通过参数的方式来传递数据,从而实现数据和脚本分离。并且可以实现用例的重复执行。(在书写用例方法的时候,测
试数据使用变量代替,在执行的时候进行据说传递)
- unittest 测试框架,本身不支持参数化,但是可以通过安装unittest扩展插 件 parameterized 来实现。

使用

1. 导包 from para... import para...
2. 修改测试方法,将测试方法中的测试数据使用 变量表示
3. 组织测试数据,格式 [(), (), ()], 一个元组就是一组测试数据
4. 参数化,在测试方法上方使用装饰器 @parameterized.expand(测试数据)
5. 运行(直接 TestCase 或者 使用 suite 运行)
import unittest

from tools import add

from parameterized import parameterized
data = [(1, 1, 2), (1, 2, 3), (2, 3, 5), (4, 5, 9)]

class TestAdd(unittest.TestCase):
    @parameterized.expand(data)
    
    
    def test_add(self, a, b, expect):
        print(f'a:{a}, b:{b}, expect:{expect}')
        self.assertEqual(expect, add(a, b))
        
        
if __name__ == '__main__':
	unittest.main()

练习

将测试数据 定义为 json 文件, 读取 json 文件,完成参数化
  • json 文件

    [
        [1, 1, 2],
        [1, 2, 3],
        [2, 3, 5],
        [4, 5, 9],
        [10, 20, 30]
    ]
    
  • 读取 json 文件

    import json
    
    
    def build_add_data():
        with open('add_data.json') as f:
       		data = json.load(f) # [[], [], []] ---> [(), ()]
            
            
        return data
    
    
  • 代码文件

    import unittest
    
    
    from read_data import build_add_data
    from tools import add
    from parameterized import parameterized
    data = [(1, 1, 2), (1, 2, 3), (2, 3, 5), (4, 5, 9)]
    
    
    class TestAdd(unittest.TestCase):
        @parameterized.expand(build_add_data())
    	def test_add(self, a, b, expect):
            print(f'a:{a}, b:{b}, expect:{expect}')
    		self.assertEqual(expect, add(a, b))
            
            
    if __name__ == '__main__':
    	unittest.main()
    

生成HTML测试报告


使用第三方的报告模版,生成报告 HTMLTestReport, 本质是 TestRunner


- 安装
pip install -i https://pypi.douban.com/simple/ HTMLTestReport


- 使用
1. 导包 unittest、HTMLTestReport
2. 组装用例(套件, loader )
3. 使用 HTMLTestReport 中的 runner 执行套件
4. 查看报告
import unittest
from htmltestreport import HTMLTestReport
from hm_04_pa1 import TestAdd

# 套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))

# 运行对象
# runner = HTMLTestReport(报告的文件路径后缀.html, 报告的标题, 其他的描述信息)
runner = HTMLTestReport('test_add_report.html', '加法用例测试报告', 'xxx')
runner.run(suite)

使用绝对路径

将来的项目是分目录书写的, 使用相对路径,可能会出现找不到文件的情况,此时需要使用 绝对路径
方法:
1. 在项目的根目录,创建一个 Python 文件(app.py 或者 config.py)
2. 在这个文件中 获取项目的目录,在其他代码中使用 路径拼接完成绝对路径的书写

import os
# __file__ 特殊的变量,表示当前代码文件名
# path1 = os.path.abspath(__file__)
# print(path1)
# path2 = os.path.dirname(path1)
# print(path2)
# BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(__file__)


if __name__ == '__main__':
	print(BASE_DIR)

案例

1, 对登录函数进行测试, 登录函数 定义在 tools.py 中
2, 在 case 目录中书写用例对login 函数进行测试, 使用断言
3, 将 login 函数的测试数据定义在 json 文件中,完成参数化, data 目录中
4, 生成测试报告 report 目录中
#测试数据的json文件
#login_data.json
[
  {
    "desc": "正确的用户名和密码",
    "username": "admin",
    "password": "123456",
    "expect": "登录成功"
  },
  {
    "desc": "错误的用户名",
    "username": "root",
    "password": "123456",
    "expect": "登录失败"
  },
  {
    "desc": "错误的密码",
    "username": "admin",
    "password": "123123",
    "expect": "登录失败"
  },
  {
    "desc": "错误的用户名和密码",
    "username": "root",
    "password": "123123",
    "expect": "登录失败"
  }
]
#读取测试数据
#read_data.py
def build_login_data():
    with open(BASE_DIR + '/data/login_data.json', encoding='utf-8') as f:
        data_list = json.load(f)  # [{}, {}] ---> [()]
        new_list = []
        for data in data_list:
            # 字典中的 desc 不需要
            username = data.get('username')
            password = data.get('password')
            expect = data.get('expect')
            new_list.append((username, password, expect))

        return new_list
#Suite 报告代码
#login.py
import unittest

from app import BASE_DIR
from case.test_login import TestLogin
from htmltestreport import HTMLTestReport

suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLogin))

runner = HTMLTestReport(BASE_DIR + '/report/login_report.html', '登录测试报告', 'V1.0')
runner.run(suite)

跳过

跳过:对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行(简单来说, 不想执行的测试方法,可以设置为跳过)

- 直接将测试函数标记成跳过
	@unittest.skip('跳过的原因')

- 根据条件判断测试函数是否跳过
	@unittest.skipIf(判断条件, reason='原因') # 判断条件为 True, 执行跳过
import unittest

version = 29


class TestSkip(unittest.TestCase):
    @unittest.skip('没什么原因,就是不想执行')
    def test_1(self):
        print('方法一')

    @unittest.skipIf(version >= 30, '版本号大于等于 30, 测方法不用执行')
    def test_2(self):
        print('方法二')

    def test_3(self):
        print('方法三')


if __name__ == '__main__':
    unittest.main()

DAY-09课堂笔记


UnitTest基本使用

UnitTest框架介绍

  • 框架

    什么是框架?
    1. 框架英文单词framework
    2. 为解决一类事情的功能集合
    
  • UnitTest框架

    是Python自带的一个单元测试框架
    - ⾃带的, 可以直接使⽤, 不需要单外安装
    - 测试⼈员 ⽤来做⾃动化测试, 作为⾃动化测试的执⾏框架, 即 管理和执⾏⽤例的
    
  • 为什么使用UnitTest框架?

    1. 能够组织多个用例去执行
    2. 提供丰富的断言方法
    3. 能够生成测试报告
    
  • UnitTest 核心要素(组成)

    1. TestCase 测试⽤例, 这个测试⽤例是 unittest 的组成部分,作⽤是 ⽤来书写真正的⽤例代码(脚本)
    
    2. Testsuite 测试套件, 作⽤是⽤来组装(打包)TestCase(测试⽤例) 的,即 可以将多个⽤例脚本⽂件 组装到⼀起
    
    3. TestRunner 测试执⾏(测试运⾏), 作⽤ 是⽤例执⾏TestSuite(测试套件)的
    
    4. TestLoader 测试加载, 是对 TestSuite(测试套件) 功能的补充, 作⽤是⽤来组装(打包) TestCase(测试⽤例) 的
    
    5. Fixture 测试夹具, 是⼀种代码结构, 书写 前置⽅法(执⾏⽤例之前的⽅法)代码 和后置⽅法(执⾏⽤例之后的⽅法) 代码 ,即 ⽤例执⾏顺序 前置 ---> ⽤例 ---> 后置
    

TestCase 测试⽤例

书写真正的⽤例代码(脚本)
单独⼀个测试⽤例 也是可以执⾏
  • 步骤:

    1. 导包 unittest
    2. 定义测试类, 需要继承 unittest.TestCase 类, 习惯性类名以 Test 开头
    3. 书写测试⽅法, 必须以 test 开头
    4. 执⾏
    
  • 注意事项

    1. 代码⽂件名字 要满⾜标识符的规则
    2. 代码⽂件名 不要使⽤中⽂
    
  • 代码

    # 1. 导包
    import unittest
    
    
    # 2. 定义测试类:新建 测试类 ;只要继承unittest.TestCase类,就是测试类
    class TestDemo(unittest.TestCase):
    
        # 3. 定义测试方法:测试方法名称命名必须以test开头
        def test_01(self):
            print("测试一")
    
        def test_02(self):
            print("测试二")
    
    # 4.执行
    # 4.1 在类名或者⽅法名后边右键运⾏
    # 4.1.1 在类名后边, 执⾏类中的所有的测试⽅法
    # 4.1.2 在⽅法名后边, 只执⾏当前的测试⽅法
    
    

TestSuite 测试套件 和 TextTestRunner 测试执⾏

TestSuite(测试套件)

将多条⽤例脚本集合在⼀起,就是套件, 即⽤来组装⽤例的
  • 步骤

    1. 导包 unittest
    2. 实例化套件对象 unittest.TestSuite()
    3. 添加⽤例⽅法
    

TextTestRunner 测试执⾏

⽤来执⾏套件对象
  • 步骤

    1. 导包 unittest
    2. 实例化 执⾏对象 unittest.TextTestRunner()
    3. 执⾏对象执⾏ 套件对象 执⾏对象.run(套件对象)
    

整体步骤

1. 导包 unittest
2. 实例化套件对象 unittest.TestSuite()
3. 添加⽤例⽅法
-  3.1 套件对象.addTest(测试类名('测试⽅法名'))
4. 实例化 执⾏对象 unittest.TextTestRunner()
5. 执⾏对象执⾏ 套件对象 执⾏对象.run(套件对象)
# 1. 导包 unittest
import unittest
from TestCase import TestDemo
from TestCase_01 import TestDemo01

# 2. 实例化套件对象 unittest.TestSuite()
suite = unittest.TestSuite()
# 3. 添加⽤例⽅法
# -  3.1 套件对象.addTest(测试类名('测试⽅法名'))
suite.addTest(TestDemo('test_01'))
suite.addTest(TestDemo('test_02'))
suite.addTest(TestDemo01('test_03'))
suite.addTest(TestDemo01('test_04'))

# -  3.2套件对象.addTest(unittest.makeSuite(测试类名)) # 在
不同的 Python 版本中,可能没有提示
suite.addTest(unittest.makeSuite(TestDemo1))
suite.addTest(unittest.makeSuite(TestDemo2))

#  - 3.3
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestDemo1))
suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestDemo2))

# 4. 实例化 执⾏对象 unittest.TextTestRunner()

runner = unittest.TextTestRunner()
# 5. 执⾏对象执⾏ 套件对象 执⾏对象.run(套件对象)
runner.run(suite)

TestLoader 测试加载

作⽤和 TestSuite 作⽤⼀样,组装⽤例代码, 同样也需要使⽤TextTestRunner() 去执⾏

需要使用10 个⽤例脚本 makeSuite()

使用unittest.TestLoader,通过该类下面的discover()方法自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件。

步骤

1. 导包 unittest
2. 实例化加载对象并加载⽤例 ---> 得到的是 套件对象(最终返回的还是测试套件对象,运行测试套件还需要使用TestRunner)
3. 实例化执⾏对象并执⾏
import unittest

# 实例化加载对象并加载⽤例,得到套件对象
# suite = unittest.TestLoader().discover('⽤例所在的⽬录', '⽤例代码⽂件名*.py')
suite = unittest.TestLoader().discover("./", "hm_02*.py")

# runner=unittest.TextTestRunner()
# runner.run(suite)

unittest.TextTestRunner().run(suite)

练习

1.

1. 创建⼀个⽬录 case, 作⽤就是⽤来存放⽤例脚本,
2. 在这个⽬录中创建 5 个⽤例代码⽂件 , test_case1.py
...
3. 使⽤ TestLoader 去执⾏⽤例
-----
将来的代码 ⽤例都是单独的⽬录 中存放的
test_项⽬_模块_功能.py
import unittest

suite = unittest.TestLoader().discover('case', 'test_case*.py')

unittest.TextTestRunner().run(suite)

2.

1. 定义⼀个 tools 模块, 在这个模块中 定义 add 的⽅法,可
以对两个数字求和,返回求和结果
2. 书写⽤例, 对 add() 函数进⾏测试
1, 1, 2
1, 2, 3
3, 4, 7
4, 5, 9
-----
之前的测试⽅法,直接⼀个 print
这个案例中的 测试⽅法,调⽤ add 函数, 使⽤ if 判断,来判断
预期结果和实际结果是否相符
预期结果 2 3 7 9
实际结果 调⽤ add()
import unittest
from tools import add

class testadd(unittest.TestCase):
    def test1(self):
        """1,1,2"""
        print(f"测试数据为:{1},{1},{2}")
        if 2==add(1,1):
            print(f"测试数据为:{1},{1},{2}通过")
        else:
            print(f"测试数据为:{1},{1},{2}不通过")


    def test2(self):
        """1,2,3"""
        print(f"测试数据为:{1},{2},{3}")
        if 3==add(1,2):
            print(f"测试数据为:{1},{2},{3}通过")
        else:
            print(f"测试数据为:{1},{2},{3}不通过")


    def test3(self):
        """3,4,7"""
        print(f"测试数据为:{3},{4},{7}")
        if 3==add(1,2):
            print(f"测试数据为:{3},{4},{7}通过")
        else:
            print(f"测试数据为:{3},{4},{7}不通过")

    def test4(self):
        """4,5,9"""
        print(f"测试数据为:{4},{5},{9}")
        if 3==add(1,2):
            print(f"测试数据为:{4},{5},{9}通过")
        else:
            print(f"测试数据为:{4},{5},{9}不通过")

Fixture

代码结构, 在⽤例执⾏前后会⾃动执⾏的代码结构
tpshop 登录
1. 打开浏览器 (⼀次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码1,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码2,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码3,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
5. 关闭浏览器 (⼀次)

方法级别Fixture

在每个⽤例执⾏前后都会⾃动调⽤, ⽅法名是固定的
def setUp(self): # 前置
 # 每个⽤例执⾏之前都会⾃动调⽤
 pass


def tearDown(self): # 后置
 # 每个⽤例执⾏之后 都会⾃动调⽤
 pass
# ⽅法前置 ⽤例 ⽅法后置
# ⽅法前置 ⽤例 ⽅法后置

类级别Fixture

在类中所有的测试⽅法执⾏前后 会⾃动执⾏的代码, 只执⾏⼀次
# 类级别的 Fixture 需要写作类⽅法
@classmethod
def setUpClass(cls): # 类前置
 	pass


@classmethod
def tearDownClass(cls): # 后置
 	pass
# 类前置 ⽅法前置 ⽤例 ⽅法后置 ⽅法前置 ⽤例 ⽅法后置类后置

模块级别Fixture(了解)

模块, 就是代码⽂件
模块级别 在这个代码⽂件执⾏前后执⾏⼀次
# 在类外部定义函数
def setUpModule():
     pass
    
    
def tearDownModule():
     pass
实现:
tpshop 登录
1. 打开浏览器 (⼀次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码1,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码2,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
2. 打开⽹⻚,点击登录 (每次)
3. 输⼊⽤户名密码验证码3,点击登录 (每次, 测试⽅法)
4. 关闭⻚⾯ (每次)
5. 关闭浏览器 (⼀次)
import unittest


class TestLogin(unittest.TestCase):

    @classmethod
    def setUpClass(cls) -> None:
        print("1.打开浏览器")

    def setUp(self) -> None:
        print("2.打开⽹⻚, 点击登录")

    def test1(self):
        print('3. 输⼊⽤户名密码验证码1,点击登录 ')

    def test2(self):
        print('3. 输⼊⽤户名密码验证码1,点击登录 ')

    def test3(self):
        print('3. 输⼊⽤户名密码验证码1,点击登录 ')

    def tearDown(self) -> None:
        print("4.关闭网页")

    @classmethod
    def tearDownClass(cls) -> None:
        print("5.关闭浏览器")

DAY-10课堂笔记


断言

使用代码自动的判断预期结果和实际结果是否相符

assertEqual(预期结果,实际结果)
- 判断预期结果和实际结果是否相等,如果相等, 用例通过,如果不相等,抛出异常, 用例不通过

assertIn(预期结果,实际结果)
- 判断预期结果是否包含在 实际结果中, 如果存在,用例通过, 如果不存在,抛出异常,用例不通过
import unittest
class TestAssert(unittest.TestCase):
	def test_equal_1(self):
		self.assertEqual(10, 10) # 用例通过
	def test_assert_2(self):
		self.assertEqual(10, 11) # 用例不通过
	def test_in(self):
        # self.assertIn('admin', '欢迎 admin 登录') # 包含 通过
        # self.assertIn('admin', '欢迎 adminnnnnnnn 登录') # 包含 通过
        # self.assertIn('admin', '欢迎 aaaaaadminnnnnnnn 登录') # 包含 通过
        # self.assertIn('admin', '欢迎 adddddmin 登录') # 不包含 不通过
		self.assertIn('admin', 'admin') # 包含 通过
import unittest

from hm_02_assert import TestAssert

suite = unittest.TestSuite()

suite.addTest(unittest.makeSuite(TestAssert))
unittest.TextTestRunner().run(suite)

参数化

- 通过参数的方式来传递数据,从而实现数据和脚本分离。并且可以实现用例的重复执行。(在书写用例方法的时候,测
试数据使用变量代替,在执行的时候进行据说传递)
- unittest 测试框架,本身不支持参数化,但是可以通过安装unittest扩展插 件 parameterized 来实现。

使用

1. 导包 from para... import para...
2. 修改测试方法,将测试方法中的测试数据使用 变量表示
3. 组织测试数据,格式 [(), (), ()], 一个元组就是一组测试数据
4. 参数化,在测试方法上方使用装饰器 @parameterized.expand(测试数据)
5. 运行(直接 TestCase 或者 使用 suite 运行)
import unittest

from tools import add

from parameterized import parameterized
data = [(1, 1, 2), (1, 2, 3), (2, 3, 5), (4, 5, 9)]

class TestAdd(unittest.TestCase):
    @parameterized.expand(data)
    
    
    def test_add(self, a, b, expect):
        print(f'a:{a}, b:{b}, expect:{expect}')
        self.assertEqual(expect, add(a, b))
        
        
if __name__ == '__main__':
	unittest.main()

练习

将测试数据 定义为 json 文件, 读取 json 文件,完成参数化
  • json 文件

    [
        [1, 1, 2],
        [1, 2, 3],
        [2, 3, 5],
        [4, 5, 9],
        [10, 20, 30]
    ]
    
  • 读取 json 文件

    import json
    
    
    def build_add_data():
        with open('add_data.json') as f:
       		data = json.load(f) # [[], [], []] ---> [(), ()]
            
            
        return data
    
    
  • 代码文件

    import unittest
    
    
    from read_data import build_add_data
    from tools import add
    from parameterized import parameterized
    data = [(1, 1, 2), (1, 2, 3), (2, 3, 5), (4, 5, 9)]
    
    
    class TestAdd(unittest.TestCase):
        @parameterized.expand(build_add_data())
    	def test_add(self, a, b, expect):
            print(f'a:{a}, b:{b}, expect:{expect}')
    		self.assertEqual(expect, add(a, b))
            
            
    if __name__ == '__main__':
    	unittest.main()
    

生成HTML测试报告


使用第三方的报告模版,生成报告 HTMLTestReport, 本质是 TestRunner


- 安装
pip install -i https://pypi.douban.com/simple/ HTMLTestReport


- 使用
1. 导包 unittest、HTMLTestReport
2. 组装用例(套件, loader )
3. 使用 HTMLTestReport 中的 runner 执行套件
4. 查看报告
import unittest
from htmltestreport import HTMLTestReport
from hm_04_pa1 import TestAdd

# 套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))

# 运行对象
# runner = HTMLTestReport(报告的文件路径后缀.html, 报告的标题, 其他的描述信息)
runner = HTMLTestReport('test_add_report.html', '加法用例测试报告', 'xxx')
runner.run(suite)

使用绝对路径

将来的项目是分目录书写的, 使用相对路径,可能会出现找不到文件的情况,此时需要使用 绝对路径
方法:
1. 在项目的根目录,创建一个 Python 文件(app.py 或者 config.py)
2. 在这个文件中 获取项目的目录,在其他代码中使用 路径拼接完成绝对路径的书写

import os
# __file__ 特殊的变量,表示当前代码文件名
# path1 = os.path.abspath(__file__)
# print(path1)
# path2 = os.path.dirname(path1)
# print(path2)
# BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(__file__)


if __name__ == '__main__':
	print(BASE_DIR)

案例

1, 对登录函数进行测试, 登录函数 定义在 tools.py 中
2, 在 case 目录中书写用例对login 函数进行测试, 使用断言
3, 将 login 函数的测试数据定义在 json 文件中,完成参数化, data 目录中
4, 生成测试报告 report 目录中
#测试数据的json文件
#login_data.json
[
  {
    "desc": "正确的用户名和密码",
    "username": "admin",
    "password": "123456",
    "expect": "登录成功"
  },
  {
    "desc": "错误的用户名",
    "username": "root",
    "password": "123456",
    "expect": "登录失败"
  },
  {
    "desc": "错误的密码",
    "username": "admin",
    "password": "123123",
    "expect": "登录失败"
  },
  {
    "desc": "错误的用户名和密码",
    "username": "root",
    "password": "123123",
    "expect": "登录失败"
  }
]
#读取测试数据
#read_data.py
def build_login_data():
    with open(BASE_DIR + '/data/login_data.json', encoding='utf-8') as f:
        data_list = json.load(f)  # [{}, {}] ---> [()]
        new_list = []
        for data in data_list:
            # 字典中的 desc 不需要
            username = data.get('username')
            password = data.get('password')
            expect = data.get('expect')
            new_list.append((username, password, expect))

        return new_list
#Suite 报告代码
#login.py
import unittest

from app import BASE_DIR
from case.test_login import TestLogin
from htmltestreport import HTMLTestReport

suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLogin))

runner = HTMLTestReport(BASE_DIR + '/report/login_report.html', '登录测试报告', 'V1.0')
runner.run(suite)

跳过

跳过:对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行(简单来说, 不想执行的测试方法,可以设置为跳过)

- 直接将测试函数标记成跳过
	@unittest.skip('跳过的原因')

- 根据条件判断测试函数是否跳过
	@unittest.skipIf(判断条件, reason='原因') # 判断条件为 True, 执行跳过
import unittest

version = 29


class TestSkip(unittest.TestCase):
    @unittest.skip('没什么原因,就是不想执行')
    def test_1(self):
        print('方法一')

    @unittest.skipIf(version >= 30, '版本号大于等于 30, 测方法不用执行')
    def test_2(self):
        print('方法二')

    def test_3(self):
        print('方法三')


if __name__ == '__main__':
    unittest.main()

标签:06,框架,UnitTest,self,测试,print,import,unittest,def
From: https://www.cnblogs.com/xcq-bj/p/18330844

相关文章

  • C语言day06(数组、字符数组)
    C语言day06【1】数组1》概念:具有一定顺序的若干变量的集合2》定义格式:存储类型数据类型数组名[元素的个数]例:intarr[5];//定义了一个数组arr,在内存空间中开辟了5个空间来储值在数组中保存的每一条数据都叫(元素)变量数组名:代表数组的首地址(地址常量);数组......
  • 框架升级之单例模式及统一异常处理
    单例模式单例模式(SingletonPattern)是一种常用的软件设计模式,它的主要目的是确保一个类仅有一个实例,并提供一个全局访问点来获取这个实例。单例模式在很多场景下都非常有用,比如配置文件读取、数据库连接、线程池等。使用单例模式改造数据库连接功能1.加载配置数据数据库配......
  • Java中的数据流处理框架:Apache Flink
    Java中的数据流处理框架:ApacheFlink大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨一下Java中的数据流处理框架——ApacheFlink。Flink是一款用于处理数据流和批处理的分布式处理框架。它具有高吞吐量、低延迟和容错的特性,广泛应用于实时......
  • 【论文解读】MetaGPT:用于元编程的多代理协作框架
    摘要基于大语言模型的多代理系统在解决自动化问题获得了显著进展。现有的基于大语言模型的多智能体系统已经可以解决简单的对话任务,但是对于更复杂的任务则因链式使用LLM导致的级联幻觉而导致逻辑不一致,从而变得复杂。在此,我们介绍MetaGPT,这是一种创新的元编程框架,将高效的......
  • [附开题]flask框架的校园疫情安全管理系统设计与实现tsckj(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景自新冠疫情全球爆发以来,校园作为高密度、高流动性的集体生活环境,其疫情防控工作面临着前所未有的挑战。学校师生众多,活动频繁,一旦发生疫情......
  • Css为例 Hugo博客框架编译时将Assets中未实际使用的文件引入Public
    今日作Hugo博客开发的过程中,想使用main.css作为其他css的入口,即项目仅引用main.css,子样式模块在main.css中引入。编译后发现public中仅有main.css,没有其他的css文件导致样式无法正常使用。遂寻找解决办法:在项目仅实际引用main.css的情况下,将其他css文件导入public。解决办法为引......
  • Gin框架深度解析:构建高性能Go Web应用的基石
    Gin框架深度解析:构建高性能GoWeb应用的基石在当今的Web开发领域,选择一个合适的框架对于项目的成功至关重要。Gin,作为一款用Go(Golang)语言编写的Web框架,凭借其高性能、简洁的API设计以及丰富的特性,迅速在开发者社区中崭露头角。本文将深入解析Gin框架,从其核心特性、工作原理......
  • 问题 E: 深入浅出学算法060-友好城市
    题目描述有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避......
  • CF1906C Cursed Game 题解
    题目大意交互库有一个\(3\times3\)的01矩阵\(a\),每次询问一个\(n\timesn\)的01矩阵\(b\),交互库会返回一个\((n-2)\times(n-2)\)的01矩阵\(c\),满足:\[c_{x,y}=\bigoplus\limits_{1\lei,j\le3}\left(a_{i,j}\operatorname{AND}b_{x+i-1,y+j-1}\right......
  • Go: Gin框架中的binding验证器使用指南
    Go:Gin框架中的binding验证器使用指南原创 王义杰 AI学者王义杰  2024年05月30日22:33 广东 听全文在Gin框架中,数据绑定和验证是开发API时不可或缺的部分。Gin提供了强大的binding功能,允许我们将请求的数据绑定到结构体,并通过标签进行数据验证。本文将详细讲解如......