背景介绍
进行项目交付之前,甲方通常需要开发者保证项目代码的测试覆盖率达到某个值,为此我们需要为项目中的代码编写相应的单元测试,然后把代码提交到
CI
CI
C
I
工具,运行
pi
p
e
i
l
n
e
pipeilne
p
i
p
e
i
l
n
e
并得到单元测试(后面简称
UT
UT
U
T
)代码对项目代码的覆盖率
在项目开发的过程中,若可以确定某部分代码在未来不怎么会改动,就可以为这部分代码写
UT
UT
U
T
代码了
写
U
T
前
的
准
备
工
作
写UT前的准备工作
写
U
T
前
的
准
备
工
作
一、文件夹创建
为
UT
UT
U
T
单独创建一个文件夹
te
s
t
s
tests
t
e
s
t
s
,用于存放单元测试需要用到的所有东西
![]()
二、创建测试文件
存放
UT
c
o
d
e
UT \space code
U
T
c
o
d
e
的
py
py
p
y
文件个人习惯以 ‘
te
s
t
test
t
e
s
t
_’ 开头
比如我想为项目代码里的
lo
g
i
c
logic
l
o
g
i
c
写
UT
c
o
d
e
UT \space code
U
T
c
o
d
e
,那就可以创建一个这样的文件:
![]()
三、安装
p
a
c
k
a
g
e
package
p
a
c
k
a
g
e
# Cmd code in Anaconda Prompt(Anaconda3):
pip install pytest==6.2.4
pip install pytest-cov==2.11.1
开
始
编
写
U
T
c
o
d
e
开始编写UT \space code
开
始
编
写
U
T
c
o
d
e
写
UT
c
o
d
e
UT \space code
U
T
c
o
d
e
的目的,实际上就是
验证某个代码块(通常为函数)的输出是否符合我们的预期
。其中用到的核心方法是
assert
,若输出与预期相符,则该测试函数就能成功覆盖项目代码中使用到该代码块的区域
一个简单的例子:
比如在项目代码中使用了这样的函数:
def sum_two_number(a, b):
result = a + b
return result
那么相应的测试函数可以为:
def test_sum_two_number():
a = 3
b = 2
expected_num = 5
output = sum_two_number(a, b)
assert expected_num == output
写
U
T
c
o
d
e
可
以
参
考
的
一
些
思
想
写 UT \space code 可以参考的一些思想
写
U
T
c
o
d
e
可
以
参
考
的
一
些
思
想
一、针对没有返回对象的函数
在
de
v
e
l
o
p
m
e
n
t
development
d
e
v
e
l
o
p
m
e
n
t
阶段,项目内的一些函数并不需要任何代码层面的输出,比如不需要
re
t
u
r
n
return
r
e
t
u
r
n
一个变量但是可能会在
lo
c
a
l
local
l
o
c
a
l
生成文件,对于这种函数,在你确保它肯定能正常运行(
工期很赶
)的前提下,可以简单粗暴地在测试函数中调用该函数,然后在测试函数的结尾直接
as
s
e
r
t
T
r
u
e
assert \space True
a
s
s
e
r
t
T
r
u
e
:
🔺:在被测函数能正常运行的前提下,这似乎是
万能
的方法,不过别人在看你的
UT
c
o
d
e
UT \space code
U
T
c
o
d
e
时会一脸懵逼 😛,除非真的是逼不得已要提高覆盖率或者某个函数很易懂没必要浪费精力去写,不然还是不建议这样写的
当然如果该函数生成了一个文件,那也可以选择使用
assert Path(file_path).exists()
进行简单验证
二、生成DataFrame的中间函数
这种函数的测试方法就很多了,可以视情况而定,基本思想是利用
df
df
d
f
的属性(
sh
a
p
e
、
c
o
l
u
m
n
shape、column
s
h
a
p
e
、
c
o
l
u
m
n
等)进行验证
- 若确定它的行数是固定的,直接
assert len(df) == row_number
即可;- 若确定它的
co
l
u
m
n
column
c
o
l
u
m
n
不变,可以在测试函数中直接
ha
r
d
c
o
d
e
hardcode
h
a
r
d
c
o
d
e
一个列表(columns_list),然后
assert df.columns.tolist() == columns_list
即可当然以上都是比较粗粒度层面的验证,仅作为思路提供
三、有多个输出的函数
由于一个测试函数只能存在一个
as
s
e
r
t
assert
a
s
s
e
r
t
,但我们希望在一个测试函数内尽量把所有输出都覆盖,那可以通过
元组
同时验证这些输出:
output_1, output_2 = function_1()
assert (output_1, output_2) == (expected_1, expected_2)
如
何
在
本
地
终
端
运
行
U
T
代
码
如何在本地终端运行UT代码
如
何
在
本
地
终
端
运
行
U
T
代
码
一、运行某个测试文件下的所有测试函数
python -m pytest 测试文件夹/测试函数文件
python -m pytest tests/tests_logic.py
二、运行某个测试文件下的单个测试函数(类)
python -m pytest 测试文件夹/测试函数文件/测试类(测试函数)
python -m pytest tests/test_logic.py::class(function)
三、查看某个测试文件对某文件夹的测试覆盖率
该命令运行结束后会在项目文件夹下生成一个名为
ht
m
l
c
o
v
htmlcov
h
t
m
l
c
o
v
的文件夹,里面包含多个
ht
m
l
html
h
t
m
l
格式的报告,从
in
d
e
x
.
h
t
m
l
index.html
i
n
d
e
x
.
h
t
m
l
进入,能方便地查看自己编写的测试函数覆盖了项目代码的哪些区域以及各个区域的覆盖率:
python -m pytest –cov=要看覆盖率的文件夹 测试文件夹/测试函数文件 –cov-report=html
python -m pytest --cov=src tests/test_logic.py --cov-report=html