Python-pytest、unittest

  1. pytest
  2. unittest

1、pytest

默认规则

  1. 模块名必须为test_开头或者_test结尾
  2. 类名必须为Test开头,并且不能有__init__方法
  3. 函数名和方法名必须为test开头或者结尾
  4. 执行顺序为自上而下

1.1 安装

# requirement.txt
pytest
pytest-html					# html报告插件
pytest-xdist				# 多并发执行插件
pytest-ordering				# 排序执行插件
pytest-rerunfailures		# 重测插件
allure-pytest				# allure报告插件

# 安装
pip install -r requirement.txt

1.2 使用

语法:pytest [options] [filename/filepath/nodeid]

1.2.1 可选参数

-s:输出调试信息及打印信息
-v:输出每个案例详细信息及测试结果
-x:报错停止,后面的案例都不会运行
-n=int:多线程运行,int表示开的线程数
-k=str:筛选运行含有指定字符串的案例
-m=str:只执行被分组标记过的,str表示组名,可以使用and or not连接分组
–reruns=int:失败重跑,int表示重跑的次数
–maxfail=int:设置允许报错次数,int表示允许报错次数
–html=path:自动生成html报告,path表示生成报告的路径
–allure=path:生成allure报告的临时数据,path表示生成路径

1.2.2 命令行

# nodeid:由模块名,分隔符,文件名,类名, 方法名, 函数名组成
# test_mod.py::TestClass::test_method, 分割符为::

示例:
pytest -vs ./testcase							# 指定路径
pytest -s test_mod.py							# 指定文件
pytest -v test_mod.py::TestClass::test_method	# 指定nodeid

1.2.3 main函数

# 传参列表,每个元素都是pytest的运行参数

示例:
if __name__ == '__main__':
    pytest.main(['-vs', '-n=4'])

1.2.4 ini配置文件

1.在项目根目录创建pytest.ini(必须为这个名字)
2.添加以下信息

# pytest.ini
[pytest]					
addopts=-vs -n=2
testpaths=./testcase
python_files=test_*.py
python_classes=Test*
python_functions=test
markers=
	test01:组名1 
	test02:组名2

# 含义
[pytest] :标识声明标题,固定写法,必须写在第一行
addopts:命令参数选项,多个参数用空格隔开
testpaths:搜索路径
python_files:搜索文件规则
python_classes:搜索类规则
python_functions:搜索函数和方法规则
markers:分组配合信息

# 运行
项目根目录下,cmd内输入pytest即可

1.2.5 断言

使用assert关键字进行断言

1.3 内置装饰器

1.3.1 标记排序

@pytest.mark.run(order=1)
在函数或方法上加以上装饰器,即可排序执行
执行顺序:0和正整数 > 没标记的 > 负整数
在各个阶段,数字越小运行级别越高
order:执行顺序

示例:
@pytest.mark.run(order=1)
def test_1():
    print('test_1...')


@pytest.mark.run(order=2)
def test_2():
    print('test_2...')


@pytest.mark.run(order=-1)
def test_3():
    print('test_3...')

@pytest.mark.run(order=-2)
def test_4():
    print('test_4...')


def test_5():
    print('test_5...')

1.3.2 标记分组

@pytest.mark.groupname
标记分组,可通过配置执行分组的所有案例
groupname:组名,自定义

示例:
@pytest.mark.mm
def test_m1():
    print('test_m1...')

@pytest.mark.mm
def test_m2():
    print('test_m2...')

1.3.3 标记跳过

无条件跳过

@pytest.mark.skip(reason=None)
跳过指定函数或方法
reason:过滤原因,可选

有条件跳过

@pytest.mark.skipif(condition, reason=None)
满足条件即跳过指定函数或方法
condition:条件,bool或字符串形式的代码,成立标记,反之不标记,必选
reason:原因,可选

示例:
@pytest.mark.skip(reason='xxx')		# 无条件跳过
def test_sk1():
    print('test_sk1...')


@pytest.mark.skipif(condition=True, reason='xxx')		# 条件成立跳过
def test_sk2():
    print('test_sk2...')

1.3.4 标记失败

@pytest.mark.xfail(reason=‘test’, raises=None, condition=None)
标记预期会出现异常的测试,异常结果显示xfail,未异常显示xpass
condition:条件,bool或字符串形式的代码,成立标记,反之不标记,可选
raises:预期抛出的异常类型,符合预期显示xfail,不符合显示xpass,可选
reason:原因,可选

示例:
@pytest.mark.xfail(condition=True, reason='xxx')		# 条件成立标记
def test_xf1():
    print('test_xf1 ...')

@pytest.mark.xfail(raises=Exception)		# 符合预期错误
def test_xf2():
    print('test_xf2...')
    raise Exception('xxx')

@pytest.mark.xfail(reason='xxx')		# 标记原因
def test_xf3():
    print('test_xf3...')

1.3.5 传参

@pytest.mark.parametrize(argnames, argvalues, ids=None)
从列表或元组内依次取值,传不同值重复执行案例
argnames::参数名称,字符串(使用逗号分割变成多参数)或列表或元组,必选
argvalues:参数值,列表或元组(多参数要使用列表套元组),必选
ids: 测试id, 可选

示例:
@pytest.mark.parametrize(['a'], [(1,), (2,), (3,)])		# 列表元组形式,单参数
def test_d(a):
    print(a)

@pytest.mark.parametrize(['a', 'b'], [(1,2), (2,3), (3,4)])		# 列表元组形式,多参数
def test_d(a, b):
    print(a, b)

@pytest.mark.parametrize('a', [1,2,3])		# 字符串形式,单参数
def test_e(a):
    print(a)

@pytest.mark.parametrize('a,b', [(1,2), (2,3), (3,4)])		# 列表元组形式,多参数
def test_f(a,b):
    print(a,b)

1.4 夹具

夹具:测试前的条件和测试后处理
setup:测试之前执行
teardown:测试后执行

1.4.1 模块级别

示例:
def setup_module(args):
    print('setup_model...', args)


def teardown_module(args):
    print('teardown_model...', args)

1.4.2 函数级别

示例:
def setup_function(args):
    print('setup_function...', args)


def teardown_function(args):
    print('teardown_function...',args)

1.4.3 类级别

示例:
def setup_class(self):
	print('setup_class...')

def teardown_class(self):
	print('teardown_class...')

1.4.4 方法级别

示例:
def setup_method(self, args):
	print('setup_method...', args)

def teardown_method(self, args):
	print('teardown_method...', args)

def setup(self):
	print('setup...')

def teardown(self):
	print('teardown...')

1.4.5 自定义

使用fixture装饰器自定义夹具
fixture(scope=‘function’, params=None, autouse=False)
scope:夹具级别, session(整个项目),module,function(包含method),class
autouse:是否自动使用

定义夹具
无返回值:
@pytest.fixture()
def custom_fixture1():
    print('custom_fixture1...')

有返回值:
@pytest.fixture()
def custom_fixture2():
    print('custom_fixture2...')
    return 1

有参数:
@pytest.fixture(params=[1,2,3])
def custom_fixture3(request):
    print('custom_fixture3...', request.param)
    return request.param
使用夹具
方式一:适合无返回值
@pytest.mark.usefixtures('custom_fixture1')
def test_1():
    print('test_1...')

方式二:适合有返回值
def test_2(custom_fixture2):
    print('test_2...', custom_fixture2)

1.5 报告

1.5.1 配置及使用

1、下载allure源码包并解压(https://github.com/allure-framework/allure2/tags)
2、下载jdk并安装
3、配置allure和jdk的环境变量
4、执行案例并生成临时文件:pytest
5、生成allure报告指令:allure generate ./temp -o ./report --clean

2、unittest

默认规则

  1. 测试类必须继承于 unittest.TestCase,并且不能有__init__方法
  2. 函数名和方法名必须为test开头,且不能有参数

2.1 使用

# 写测试类,然后使用main函数运行

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

2.2 断言

使用assert关键字进行断言
使用TestCase的方法断言

TestCase的断言方法
def assertEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ...
def assertNotEqual(self, first: Any, second: Any, msg: Any = ...) -> None: ...
def assertTrue(self, expr: Any, msg: Any = ...) -> None: ...
def assertFalse(self, expr: Any, msg: Any = ...) -> None: ...
def assertIs(self, expr1: Any, expr2: Any, msg: Any = ...) -> None: ...
def assertIsNot(self, expr1: Any, expr2: Any, msg: Any = ...) -> None: ...
def assertIsNone(self, obj: Any, msg: Any = ...) -> None: ...
def assertIsNotNone(self, obj: Any, msg: Any = ...) -> None: ...
def assertIn(self, member: Any, container: Union[Iterable[Any], Container[Any]], msg: Any = ...) -> None: ...
def assertNotIn(self, member: Any, container: Union[Iterable[Any], Container[Any]], msg: Any = ...) -> None: ...
def assertIsInstance(self, obj: Any, cls: Union[type, Tuple[type, ...]], msg: Any = ...) -> None: ...
def assertNotIsInstance(self, obj: Any, cls: Union[type, Tuple[type, ...]], msg: Any = ...) -> None: ...
def assertGreater(self, a: Any, b: Any, msg: Any = ...) -> None: ...
def assertGreaterEqual(self, a: Any, b: Any, msg: Any = ...) -> None: ...
def assertLess(self, a: Any, b: Any, msg: Any = ...) -> None: ...
def assertLessEqual(self, a: Any, b: Any, msg: Any = ...) -> None: ...
...

2.3 子测试


class TestSub(unittest.TestCase):
    def test_sub(self):
        for i in range(10):
            with self.subTest(i):				# 子测试,多次执行该测试
                print(f"test_sub: {i}...")

2.4 夹具

2.4.1 模块级别

def setUpModule():
    print('setUpModule...')

def tearDownModule():
    print('tearDownModule...')

2.4.2 类级别

@classmethod
def setUpClass(cls):
    print('setUpClass...')

@classmethod
def tearDownClass(cls):
    print('tearDownClass...')

2.4.3 方法级别

def setUp(self):
    print('setUp...')

def tearDown(self):
    print('tearDown...')

2.5 测试套件

TestSuite:用来自己组织待测试的内容和顺序
TextTestRunner:执行测试并将结果写到TestResult中
HtmlTestRunner:执行测试并生成Html报告,安装:pip install html-testRunner
defaultTestLoader:根据规则自动寻找并添加case

1. 创建TestSuite对象
2. 添加测试内容
3. 运行测试

# 方法一
suite = unittest.TestSuite()			# 实例化suite对象
suite.addTest(Txt("test_02"))			# 添加一条case
suite.addTests(map(Txt, ['test_01', 'test_02']))			# 添加多条case

runner = unittest.TextTestRunner()			# 生成runner对象
runner.run(suite)			# 运行测试

# 方法二
import HtmlTestRunner
# 根据规则自动寻找并添加case,path:寻找开始路径, pattern:寻找规则,并生成suite对象
suite = unittest.defaultTestLoader.discover(path, pattern='test_*.py')

runner = HtmlTestRunner.runner.HTMLTestRunner()			# 生成runner对象
runner.run(suite)			# 运行测试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值