单元测试
https://blog.csdn.net/Tencent_TEG/article/details/115713186
单元测试,Unit Test,又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
集成测试,Integration Test,又称组装测试,即对程序模块采用一次性或增值方式组装起来,对系统的接口进行正确性检验的测试工作。集成测试一般在单元测试之后、系统测试之前进行。实践表明,有时模块虽然可以单独工作,但是并不能保证组装起来也可以同时工作。
功能测试,Functional Test:功能测试就是对产品的各功能进行验证,根据功能测试用例,逐项测试,检查产品是否达到用户要求的功能。
交互式文档测试
python -m doctest -v example.py
"""
This is the "example" module.
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
import math
def factorial(n):
"""
Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
@param n:
@return:
"""
if n < 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n + 1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
https://docs.python.org/zh-cn/3/library/doctest.html#doctest.ELLIPSIS
def xxx(x):
"""
>>> xxx(...) # doctest: +ELLIPSIS
... # 表示接着上一行
'...'
>>> xxx(1 / 0) # doctest: -ELLIPSIS
Traceback (most recent call last):
...
File "<doctest xxx[1]>", line 1, in <module>
xxx(1 / 0)
~~^~~
ZeroDivisionError: division by zero
File "<doctest xxx[1]>", line 1, in <module>!!!
:return:
"""
return str({x})
unittest
单元测试,Python标准库
- 编写单元测试时,我们需要编写一个测试类,从
unittest.TestCase继承 - 以
test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行 - 对每一类测试都需要编写一个
test_xxx()方法
https://docs.python.org/zh-cn/3/library/unittest.html
unittest
parameterized ddt
unittest.mock
coverage
coverage run -m unittest discover
coverage report -m
coverage html
pip install html-testRunner
import HtmlTestRunner
# some tests here
if __name__ == '__main__':
unittest.main(testRunner=HtmlTestRunner.HTMLTestRunner())
pytest
三方库
pip install pytest
pip install pytest-cov
pytest --version
pytest用例执行规则
pytest 会自动递归遍历执行路径下所有的目录,根据 pytest 中默认用例的识别的规则,自动收集测试用例,默认用例识别规则为:
- 用例文件:所有文件名为
test_开头 或者_test开头的文件会被识别为用例文件。 - 用例类,测试文件中每个Test开头的类就是一个测试用例类。
- 用例方法:测试类中每个test开头的方法就是一条测试用例,测试文件中每个test开头的函数也是一条测试用例,
用例识别规则可以通过配置文件配置
执行方式
使用命令行方式执行
pytest -h
# 指定测试目录
pytest testcase/
# 指定测试文件
pytest testcase/test_demo1.py
# 指定测试类
pytest testcase/test_demo1.py::TestClass
# 指定测试用例
pytest testcase/test_demo1.py::TestClass::test_method
pytest --cov=src --cov-report=html
Allure
Allure是测试报告工具,需要配合测试框架使用,如pytest
https://docs.qameta.io/allure/
https://github.com/allure-framework/allure2/releases
https://juejin.cn/post/6844904017873600520
定制报告
- Feature:标注主要功能模块
@allure.feature('test_module_01')@allure.feature('test_module_02') - Story: 标注Features功能模块下的分支功能
@allure.feature('test_module_01')@allure.story('test_story_01') - Severity:标注测试用例的重要级别
Allure中对严重级别的定义:
— Blocker级别:中断缺陷(客户端程序无响应,无法执行下一步操作)@allure.severity('blocker')
— Critical级别:临界缺陷( 功能点缺失)
— Normal级别:普通缺陷(数值计算错误)
— Minor级别:次要缺陷(界面错误与UI需求不符)
— Trivial级别:轻微缺陷(必输项无提示,或者提示不规范) - Step: 标注测试用例的重要步骤
@allure.step("字符串相加:{0},{1}") - Issue和TestCase: 标注Issue、Case,可加入URL
@allure.issue("http://www.baidu.com")@allure.testcase("http://www.testlink.com")
性能测试
https://zhuanlan.zhihu.com/p/83421076
https://blog.csdn.net/GuoQiZhang/article/details/105408009
https://blog.csdn.net/Bit_Coders/article/details/120154767
python性能分析工具
https://zhuanlan.zhihu.com/p/505344229
https://github.com/P403n1x87/austin
时间相减
时间戳相减:基本相减、装饰器实现
timeit
cProfile
import cProfile
def fun():
fun1()
def fun1():
for i in range(10):
fun2()
def fun2():
for i in range(4):
fun3()
fun4()
def fun3():
import time
time.sleep(0.1)
def fun4():
import time
time.sleep(0.01)
if __name__ == "__main__":
cProfile.run('fun()')
python -m cProfile test.py
python -m cProfile -o profile.stats test.py
生成一个统计文件然后通过python进行分析
import pstats
p = pstats.Stats(“profile.stats”)
p.print_stats()
line_profiler
用cProfile找到需要分析的函数,然后用line_profiler对函数进行分析。line_profiler可以帮你一行一行分析函数性能
pip install line_profiler
kernprof
运行kernprof 逐行分析被修饰函数的CPU开销
kernprof.py -l -v test.py
-v 显示输出
-l 代表逐行分析而不是逐函数分析
Total Time:测试代码的总运行时间
Hits:表示每行代码运行的次数
Time:每行代码运行的总时间
Per Hits:每行代码运行一次的时间
% Time:每行代码运行时间的百分比
备注
使用time.perf_counter() 能够提供给定平台上精度最高的计时器,但是,它计算的仍然是时钟时间,很多因素会影响到它的精确度,比如机器负载。
如果你对于执行时间更感兴趣,使用time.process_time() 来代替它。
Scalene
…
..
from memory_profiler import profile # pip install memory_profiler
@profile
def test_func():
o = ["AAA", "BBB", "CCC"] * 2 ** 16
a = [string for string in o]
list(a)
b = (string for string in o)
list(b)
test_func()