Pytes安装&用例执行

简介

Pytest是基于python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。

The pytest framework makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries.

pytest框架使编写小型测试变得很容易,同时还支持对应用程序和库进行复杂的功能测试。

pytest官方主页

优点

  • 允许直接使用assert进行断言,而不需要使用self.assert*;
  • 可以自动寻找单测文件、类和函数;
  • Modular fixtures可以用于管理小型或参数化的测试信息;
  • unittestnose单测框架兼容;
  • 兼容性较好,支持Python 2.7,Python 3.4+。
  • 丰富的插件支持,共计有超过315个插件支持;

安装

1.安装命令

1
pip install -U pytest

2.安装校验

1
2
pytest --version
This is pytest version 3.x.y, imported from $PYTHON_PREFIX/lib/python3.6/site-packages/pytest.py

入门使用

创建一个测试模块,test_add.py定义如下

1
2
3
4
5
6
7

def add(a,b):
return a+b

#用例名称必须是test开头
def test_add():
assert add(2,3)==4

打开cmd执行如下命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
λ pytest E:\code\learning_python\pytest_test\test_add.py
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-3.8.1, py-1.5.3, pluggy-0.7.1
rootdir: E:\, inifile:
collected 1 item

..\..\..\code\learning_python\pytest_test\test_add.py F [100%]

================================== FAILURES ===================================
__________________________________ test_add ___________________________________

def test_add():
> assert add(2,3)==4
E assert 5 == 4
E + where 5 = add(2, 3)

E:\code\learning_python\pytest_test\test_add.py:6: AssertionError
========================== 1 failed in 0.27 seconds ===========================

在pytest框架中,有如下约束:

  • 所有的单测文件名都需要满足test_*.py格式或*_test.py格式。
  • 在单测文件中,可以包含test_开头的函数,也可以包含Test开头的类。
  • 在单测类中,可以包含一个或多个test_开头的函数。

执行多个测试用例

test_class.py

1
2
3
4
5
6
7
8
9
10
11
class TestClass():
def test_one(self):
print('test one')
x='hello'
assert 'h' in x

def test_two(self):
print('test two')
y='mgtv'
assert 'm' in y

执行命令:

1
2
3
4
5
λ pytest -q -s E:\code\learning_python\pytest_test\test_class.py
test one
.test two
.
2 passed in 0.02 seconds

参数说明

  • -q安静模式运行用例,显示简要信息
  • -s显示(show)用例打印的信息

如果不加这两个参数显示效果如下:

1
2
3
4
5
6
7
8
9
λ pytest  E:\code\learning_python\pytest_test\test_class.py
============================= test session starts =============================
platform win32 -- Python 3.5.0, pytest-3.8.1, py-1.5.3, pluggy-0.7.1
rootdir: E:\, inifile:
collected 2 items

..\..\..\code\learning_python\pytest_test\test_class.py .. [100%]

========================== 2 passed in 0.04 seconds ===========================

setup与teardown

PyTest支持xUnit style 结构, setup()teardown() 方法用于初始化和清理测试环境,可以保证测试用例的独立性。pytestsetup/teardown方法包括:

  • 模块级别(setup_module/teardown_module)
  • 函数级别(setup_function/teardown_function)
  • 类级别(setup_class/ teardown_class)
  • 方法级别(setup_method/teardown_methond或者setup/teardown)

模块级别

模块中的第一个测试用例开始前执行setup_module方法,模块中的最后一个测试用例结束后运行teardown_module方法,不在测试类中。

函数级别

setup_function/teardown_function在每个测试函数前后运行,只对函数用例生效,不在类中。

类级别

类级别函数 setup_class/teardown_class 对类有效,位于类中,在测试类中前后调用一次。

方法级别

方法级别函数 setup_method/teardown_methodsetup/teardown对类有效,也位于类中,这两个效果一样,在测试类中每个测试方法前后调用一次。

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

import pytest

class TestPytest():

def setup_class(self):
print('setup_class:每个测试类开始之前都会执行')

def teardown_class(self):
print('teardown_class:每个测试类结束之后都会执行')

def setup_method(self):
print("setup_method:每个用例开始前都会执行")

def teardown_method(self):
print("teardown_method:每个用例结束后都会执行")

def test_one(self):
print("正在执行---test_one")

def test_two(self):
print("正在执行---test_two")

def login(self):
print("正在执行---test_login")

if __name__ == "__main__":
pytest.main(["-s","pytest_setup_teardown.py"])

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
============================= test session starts =============================
platform win32 -- Python 3.7.3, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: C:\Users\Shuqing\PycharmProjects\python_testframwork
collected 2 items

pytest_setup_teardown.py setup_class:每个测试类开始之前都会执行
setup_function:每个用例开始前都会执行
正在执行---test_one
.teardown_function:每个用例结束后都会执行
setup_function:每个用例开始前都会执行
正在执行---test_two
.teardown_function:每个用例结束后都会执行
teardown_class:每个测试类结束之后都会执行


============================== 2 passed in 0.03s ==============================

Process finished with exit code 0

参数化

@pytest.mark.parametrize 可以为测试方法或者测试类定义多组变量。

参数化方法如下:

1
2
3
4
5
6
7
8
@pytest.mark.parametrize(argnames, argvalues)

argnames:参数化变量名,可以是string(逗号分割) 、list 和 tuple类型

@pytest.mark.parametrize(“a, b”, [(1,2),(3,4)])
@pytest.mark.parametrize([“a”,“b”], [(1,2),(3, 4)])
@pytest.mark.parametrize((“a”, “b”), [(1,2),(3,4)])
argvalues:参数化的值

参数化案例1

1
2
3
4
5
6
7
8
9
10
11
12
import pytest

class Test_Demo():
@pytest.mark.parametrize("a, b, result", [(1, 1, 2), (2, 8, 10)])
def test_case1(self, a, b, result):
print("\n开始执行测试用例")
print(a, b, result)
assert a + b == result


if __name__ == '__main__':
pytest.main(["-s","pytest_param.py"])

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C:\python37\python.exe C:/Users/Shuqing/PycharmProjects/python_testframwork/pytest_param.py
============================= test session starts =============================
platform win32 -- Python 3.7.3, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: C:\Users\Shuqing\PycharmProjects\python_testframwork
collected 2 items

pytest_param.py
开始执行测试用例
1 1 2
.
开始执行测试用例
2 8 10
.

============================== 2 passed in 0.02s ==============================

Process finished with exit code 0

参数化案例2

数据驱动参数化的应用,数据量小的测试用例可以使用代码的参数化来实现数据驱动,数据量大的情况下可以使用一种结构化的文件(例如csv、yaml、xml、db、 excel、json等)来存储数据,然后在测试用例中读取这些数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pytest,yaml

class Test_Demo():
# @pytest.mark.parametrize("a, b, result", [(1, 1, 2), (2, 8, 10)])
@pytest.mark.parametrize("a, b, result", yaml.safe_load(open("./data.yaml")))
def test_case1(self, a, b, result):
print("\n开始执行测试用例")
print(a, b, result)
assert a + b == result


if __name__ == '__main__':
pytest.main(["-s","pytest_param.py"])

参考资料