1、引言
我有一个朋友是做Python自动化测试的。前几天他告诉我去参加一个大厂面试被刷了。
我问他是有没有总结被刷下来的原因。他说面试官问了一些 pytest 单元测试框架相关的知识,包括什么插件系统和用力筛选。但是他所在的公司用的技术是基于 unittest 的,没有用过 pytest。
我跟他说你可以和技术面试官说明,在实际过程当中你没有使用过 pytest,但是你可以后面再学。这哥们说:我就是这样跟面试官说的,但是面试官告诉我 pytest 现在已经是行业里面的主流,还在坚持用 unittest 说明我的技术已经过时了,没有跟上现在测试领域的发展。
实际上他在面试之前已经了解过 pytest 的一些基础用法,但是网上的一些资料,都是停留在用法和一些知识点的讲解,没有深入到 pytest 内部运行和一些高级特性。所以被问到的时候,自己临时抱佛脚的一些知识都没有用上。
后面我给这位朋友补习了一些关于Python的高级特性。现在我连同基础部分的内容一起贴出来,希望对Python自动化测试的一些朋友有所帮助。
2、为什么用单元测试框架?
首先我要说明一下什么是单元测试框架?
unittest 和 pytest 都是单元测试框架。单元测试指的是在编程过程当中形成的对函数或者是类下面的方法进行测试的一个过程,国内现在测试一般不做单元测试。
unittest 和 pytest 的区别:
- unittest: 内置单元测试框架,和安装的python兼容
- pytest:公司主流、功能极其强大。安装,python-pytest版本不兼容。
- nose
在不使用任何框架的前提下,其实也是可以进行单元测试的。比如我们可以通过 if 判断、assert、异常处理或者是其他的流程控制来表示测试是否通过。
例如:
用 if 进行单元测试
def add(a, b):
return a + b
def test_add():
ret = add(3, 4)
expected=7
if ret == expected:
print("add 函数的测试通过")
else:
print("add 函数的测试失败")
如果要运行这个用例,需要手工调用 test_add 这个函数
if __name__=="__main__":
test_add()
接下来,使用 python 运行这个文件,就能得到测试结果:
add 函数的测试通过
例如:
用assert进行单元测试
断言成功
def add(a, b):
return a + b
def test_add():
ret = add(3, 4)
expected=7
assert ret==expected
if __name__=="__main__":
test_add()
接下来,使用 python 运行这个文件,就能得到测试结果:
##运行结果为空
断言失败
def add(a, b):
return a + b
def test_add():
ret = add(3, 4)
expected=8
assert ret==expected
if __name__=="__main__":
test_add()
接下来,使用 python 运行这个文件,就能得到测试结果:
Traceback (most recent call last):
File "E:/software/test/Pycharm-Workspace/test.1.py", line 9, in <module>
test_add()
File "E:/software/test/Pycharm-Workspace/test.1.py", line 7, in test_add
assert ret==expected
AssertionError
说明:
利用assert进行断言,如果断言成功,则什么也不打印,如果断言失败则会报错
虽然说上面我们通过 if 判断,assert 对一个函数进行了测试,而且得到了测试结果,但是流程是比较复杂的:
-
首先我们需要人工去判断结果,
-
第2我们需要通过 Python去运行模块。
-
第3,我们还需要显性的去调用 test_add 这个函数。
这还只是在我们只测试了一个函数的情况下,当需要测试的函数或者类越来越多的时候,这个过程会越来越复杂。
而使用单元测试框架,可以极大的简化我们对单元测试的过程,使用单元测试框架以后,框架会提供各种各样的工具和手段,帮我们自动去收集用例、运行用例、生成报告,辅助你提升效率
为什么使用框架的总结:
手工:
- 手工调用测试函数
- 手工去管理测试中断
- 手工生成测试报告。
框架:
- 而框架是可以解决手工的这些问题
3、pytest 的基础使用
因为 pytest 是一个第三方的框架,所以我们先要安装。安装方式非常简单,只需要通过 pip 这个包管理工具安装就可以了。
pytest 安装命令
pip install pytest
更新pytest
pip install -U pytest
查看是否安装成功
pip list
使用 pytest
写完测试用例以后,我们只需要在目录下输入pytest 指令,就可以自动运行用例,而且呢结果会直接显示在命令行的下方。
强制显示打印信息
pytest -s
上面讲的是单元测试过程,也就是说对某个函数或者是类下面的方法进行测试,有的人可能会不理解。在实际工作过程当中很少进行单元测试啊,测试人员做的更多的是接口测试,UI测试,pytest 怎么用呢?
实际上不管是接口测试还是UI测试,都是可以使用 pytest。当你进行接口测试的时候,你只需要把访问接口的过程封装成一个Python函数。
def visit_api():
print("访问接口,得到结果...")
return response
def test_api():
assert expected_response == visit_api()
当你进行 web测试的时候,你只需要操作浏览器的过程封装成一个函数?
def browser_method():
print("点点点")
return ui_response
def test_web():
assert expected_response == browser_method()
在这种情况下。接口访问和web操作都是以函数形式存在的,我们直接去测试这个 Python 函数,也是一个单元测试的过程。
安装完成以后,我们可以向使用上面的那个例子一样:
-
第1步:定义一个测试函数,这个测试函数通常会调用被测函数。
-
第2步:使用assert断言,assert 后面可以跟任意的 Python 条件表达式。
assert 4 < 5
assert "yuze" in "yuze wang"
assert isinstance(6, int)
运行测试用例的结果分析
写完测试用例以后,我们只需要在目录下输入pytest 指令,就可以自动运行用例,而且呢结果会直接显示在命令行的下方。
例行用了以后呢,在命令行当中会显示4个部分的内容:
-
第1个部分,测试用例和通过的结果,
-
第2个部分,失败用例回溯信息,
-
第3个部分,输出捕获信息,
-
第4个部分,总结信息。
F:代表失败
.:代表成功
-
Captured stdout call 只有在用例失败的时候才会出现
在pytest当中通过的测试用例,不会有特别详细的结果,但是失败的测试用例默认会有非常详细的结果,而且会帮你捕获错误原因。
如果想要通过的测试用例也打印出详细的信息,就要在执行的时候加上 -s ----> pytest -s
下面是通过的测试用例
测试用例的编写需要遵循的规则
- 模块是以 test_*.py
- 可以以 *_test.py
- 函数 test_
- 如果写在类下面,类 Test
- 不需要 return
- 不要自己去调用 test_
- 函数参数不要随意加。
收集用例:
注意:一定要在指定目录下运行 pytest
运行某个模块下的用例:
方法一:在命令行中输入 pytest 模块名.py
方法二:右点击 --> run pytest in 模块名;
注意:(右击运行的时候要 在最后空白行定格运行)
方法三:
导入pytest,直接右键在python中执行就可以
import pytest
if __name__ == '__main__':
pytest.main()
测试报告
pytest的插件有非常非常多,有大概1000多种
安装插件
pip install pytest-html
使用插件输出报告
pytest --html=路径\报告名称.html
pytest的标记功能
mark
1, 在用例的上方加上@pytest.mark.标签名称
2. 在命令行中输入:pytest -m "标签名" ,这样就会运行标签的用例了
3. pytest 的配置文件当中注册 smoke(如果没有注册ini配置文件,不会报错,会警告)
建一个名为pytest.ini的配置文件
[pytest]
markers =
smoke
例如:
import pytest
def add(a, b):
"""开发人员写的函数"""
return a + b
@pytest.mark.smoke
def test_add():
"""封装起来的测试过程,自动化测试用例。
test_ 开头的函数
"""
ret = add(3, 4)
expected = 8
# if ret == expected:
# print("测试用例通过")
# else:
# print("测试用例不通过")
# 断言
# 如果 assert 通过,程序正常执行。
# assert 不通过,会报错,AssertionError
# try:
# assert expected == ret
# except AssertionError as e:
# logging.error("断言失败",e)
assert expected == ret
def test_minus():
print("第二个用例")
assert 3 - 2 == -1
# if __name__ == '__main__':
# test_add()
# test_minus()
例如:
写一个登陆函数,输入用户名和密码,如果用户名='yuz' 并且 密码 = ‘123456’ 返回 ”登陆成功“, 否则返回”登陆失败“
编写测试用例函数,测试上面的登陆函数。至少 3 个测试用例。
使用 pytest 运行登陆成功用例。 (可以把运行的命令作为注释写在模块中)。
def login(username, password):
"""开发写的功能"""
if username == 'yuz' and password == '123456':
return "登陆成功"
return "登陆失败"
#测试用例里面不要传参数
#右击运行的时候要在最后空白行定格运行
# #不需要 return
def test_login_1():
"""第一个用例"""
u = ''
p = ''
expected = '登陆失败'
ret = login(u, p)
assert ret == expected
def test_login_2():
"""第一个用例"""
u = 'a'
p = 'b'
expected = '登陆失败'
ret = login(u, p)
assert ret == expected
def test_login_3():
"""第一个用例"""
u = 'yuz'
p = '123456'
expected = '登陆成功'
ret = login(u, p)
assert ret == expected