# 测试 LLM 的 assert 功能
# 1_PythonProjectTemplate-master
运行 pip install -e .
和 pytest tests
后出现下图,表明本地构建和安装和测试项目成功。
然后再运行 pytest --cov=fastvector tests --cov-report=html
来生成代码覆盖率报告
<img src="D:\desktop\Code_Compiling\LLM 的 test_oracle 生成 \0_readme_picture\1.png" alt="1" style="zoom:50%;" />
# test 代码修改
# test 初始代码
1 | """ Unit Test Cases """ |
从 test 代码中我们可知:test_from_values、test_repr、test_str、test_add、test_sub、test_mul_vec、test_mul_float、test_div、test_abs、test_equality_other_class、test_less_than 中有 assert 语句。
将 assert 语句删除,并且删掉提示字符串,然后将代码交给 gpt3.5 进行修改。
提示语句为 “这个 test case 缺少 assert 语句 请补全”
# test 投喂代码
1 | """ Unit Test Cases """ |
# test 代码分析
gpt3.5 修改后的 test 语句为:
1 | """ Unit Test Cases """ |
# 比对修改前后代码块的作用
对于
test_init_raises()
函数,其用于验证创建的Vector2D
对象是否与预期结果exp
相等。—— 修改前后代码作用相同对于
test_repr和test_str
函数:
修改前:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def test_repr(
capture_stdout: dict[str, Any],
) -> None:
"""Test repr."""
print(repr(Vector2D(1.0, 2.0)))
assert capture_stdout["stdout"] == "vector.Vector2D(1.0, 2.0)\n"
def test_str(
capture_stdout: dict[str, Any],
) -> None:
"""Test str."""
print(str(Vector2D(1.0, 2.0)))
assert capture_stdout["stdout"] == "(1.0, 2.0)\n"其作用为验证 Vector2D 对象的 '__repr__' 方法的输出。通过建立字典 capture_stdout 来捕获 capture_stdout。print 函数的目的为将
Vector2D(1.0, 2.0)
对象的__repr__
方法的输出打印到标准输出。以便实际使用时开发者可以看到程序输出结果,帮助理解程序执行的结果和确保__repr__
方法的实现符合预期。 然后使用assert capture_stdout["stdout"] == "vector.Vector2D(1.0, 2.0)\n
" 来验证捕获的输出与预期输出是否相符。
gpt3.5 补充后:1
2
3
4
5
6
7def test_repr() -> None:
assert repr(Vector2D(1.0, 2.0)) == "Vector2D(1.0, 2.0)"
def test_str() -> None:
assert str(Vector2D(1.0, 2.0)) == "(1.0, 2.0)"缺点:
- 功能减少:一般来说为了符合开发者调试,test 时需要 print 函数以便开发者了解程序的输出,gpt 填充的 assert 里忽略了 print,直接对比返回值,其只适用于
repr
和str
函数的输出场景 - 调试困难:如果我们 assert 报错后,最初的代码可以通过 print 来留下更多的调试信息,而 gpt 生成的返回值无法做到这一步,需要额外增加 print 代码来了解报错原因
改进:当我们给 gpt 输入:“这个 test case 缺少 assert 语句 请补全,要求调试的过程中方便开发者直观看到输出过程” 后,代码输出增加了 print 语句,优化成功。
- 功能减少:一般来说为了符合开发者调试,test 时需要 print 函数以便开发者了解程序的输出,gpt 填充的 assert 里忽略了 print,直接对比返回值,其只适用于
test_add
和test_sub
和test_mul_float``test_div
和 'test_abs' 和 'test_less_than' 函数:验证两个Vector2D
对象相加 / 减 / 乘 / 除 / 取绝对值 / 是否小于的结果是否与预期结果相等。gpt 改后与之前效果相同。
# LLM 生成代码分析
# LLM 修改后与原来一致:
assert exp == Vector2D(x, y)
assert capture_stdout["stdout"] == "vector.Vector2D(1.0, 2.0)
assert capture_stdout["stdout"] == "(1.0, 2.0)\n"
assert lhs + rhs == exp_res
assert lhs - rhs == exp_res
assert lhs * rhs == exp_res
assert lhs * rhs == exp_res
assert lhs / rhs == exp_res
assert abs(rhs) == lhs
assert lhs != rhs
assert rhs < lhs
# LLM 修改后与原来不同:
无
# LLM 生成代码与原代码一致的概率
100%
# 分析一:断言在验证的东西
assert exp == Vector2D(x, y)
- 使用参数化设置,传入不同的 x 和 y 值,以及期望的 Vector2D (x,y) 对象 'exp'
- 测试通过创建一个新的 Vector2D 对象并将其与预期的对象进行比较来验证初始化是否正确
assert capture_stdout["stdout"] == "vector.Vector2D(1.0, 2.0)\n"
- 验证
repr
方法返回的Vector2D
对象是否用正确字符串表示
- 验证
assert capture_stdout["stdout"] == "(1.0, 2.0)\n"
- 验证
str
方法返回的Vector2D
对象是否用正确字符串表示
- 验证
assert lhs + rhs == exp_res
- 验证两个
Vector2D
对象相加的结果是否正确。
- 验证两个
assert lhs - rhs == exp_res
- 验证两个
Vector2D
对象相减的结果是否正确。
- 验证两个
assert lhs * rhs == exp_res
- 验证两个
Vector2D
对象相乘(点积)的结果是否正确。
- 验证两个
assert lhs * rhs == exp_res
——test_mul_float
- 验证
Vector2D
对象与浮点数相乘的结果是否正确。
- 验证
assert lhs / rhs == exp_res
- 证
Vector2D
对象与浮点数相除的结果是否正确。
- 证
assert abs(rhs) == lhs
- 验证
Vector2D
对象的绝对值(模)是否正确。
- 验证
assert lhs != rhs
- 验证当
Vector2D
对象与不同类对象进行比较时,是否返回False
- 验证当
assert rhs < lhs
- 验证
Vector2D
对象的 “小于” 比较运算是否正确。
- 验证
# 分析二:断言是否依赖于具体的 SUT (被测软件) 的输出及原因
assert exp == Vector2D(x, y)
- 依赖
- 这个测试通过创建
Vector2D
对象来验证其初始化功能 - 断言
exp == Vector2D(x, y)
依赖于Vector2D
的__eq__
方法是否正确实现。 - 如果
Vector2D
类的初始化或__eq__
方法有问题,这个断言将无法通过。因此,断言依赖于Vector2D
类的具体实现(即 SUT 的输出)。
assert capture_stdout["stdout"] == "vector.Vector2D(1.0, 2.0)\n"
- 依赖
- 断言
capture_stdout["stdout"] == "vector.Vector2D(1.0, 2.0)\n"
依赖于__repr__
方法的具体输出。 - 也依赖 Vector2D (1.0,2.0) 的具体输出
assert capture_stdout["stdout"] == "(1.0, 2.0)\n"
- 依赖
- 它依赖于
Vector2D
类中__str__
方法的具体实现。
assert lhs + rhs == exp_res
- 依赖
- 依赖于
Vector2D
类中__add__
方法的具体实现。
assert lhs - rhs == exp_res
- 依赖
- 依赖于
Vector2D
类中__sub__
方法的具体实现。
assert lhs * rhs == exp_res
- 依赖
- 它依赖于
Vector2D
类中__mul__
方法对另一个Vector2D
对象的具体实现。
assert lhs * rhs == exp_res
——test_mul_float
- 依赖
- 依赖于
Vector2D
类中__mul__
方法对浮点数的具体实现。
assert lhs / rhs == exp_res
- 依赖
- 依赖于
Vector2D
类中__truediv__
方法的具体实现
assert abs(rhs) == lhs
- 它依赖于
Vector2D
类中__abs__
方法的具体实现。
- 它依赖于
assert lhs != rhs
- 它依赖于
Vector2D
类中__eq__
方法的具体实现。
- 它依赖于
assert rhs < lhs
- 它依赖于
Vector2D
类中__lt__
方法的具体实现。
- 它依赖于
# 分析三:断言为何能生成
assert exp == Vector2D(x, y)
- 函数名:投喂给 LLM 的函数名为
test_from_values
,即从数值上进行比较,而函数中对 x,y 进行初始化,并且定义了一个 exp=Vector2D,故 LLM 可以判断断言为判断 exp 是否和 Vector2D (x,y) 相等
- 函数名:投喂给 LLM 的函数名为
assert capture_stdout["stdout"] == "vector.Vector2D(1.0, 2.0)\n"
- 函数名,投喂给 LLM 的函数名为
test_repr
,即为测试该 Vector2D 的标准字符串表示 - 在代码里出现了 capture_stdout,即为捕获标准输出。
- 函数里出现
print(repr(Vector2D(1.0, 2.0)))
,即可知道需要对于标准输出和repr(Vector2D(1.0, 2.0))
进行对比 - 故 LLM 可以依此来判定断言
- 函数名,投喂给 LLM 的函数名为
assert capture_stdout["stdout"] == "(1.0, 2.0)\n"
- 函数名,投喂给 LLM 的函数名为
test_str
,即为测试该 Vector2D 的字符串表示 - 在代码里出现了 capture_stdout,即为捕获标准输出。
- 函数里出现
print(repr(Vector2D(1.0, 2.0)))
,即可知道需要对于标准输出和str(Vector2D(1.0, 2.0))
进行对比 - 故 LLM 可以依此来判定断言
- 函数名,投喂给 LLM 的函数名为
assert lhs + rhs == exp_res
- 函数名为
test_add
, 即为测试 add 方法 - 函数中出现了 lhs,rhs 和 exp_res
- 故 LLM 可以判定方法为测试相加是否相等
- 函数名为
assert lhs - rhs == exp_res
- 函数名为
test_sub
, 即为测试 add 方法 - 函数中出现了 lhs,rhs 和 exp_res
- 故 LLM 可以判定方法为测试相减是否相等
- 函数名为
assert lhs * rhs == exp_res
- 函数名为 test_mul_vec,即为测试相乘是否结果一致
- 出现了 lhs,rhs,exp_res 的初始化定义
- 故 LLM 可以判定方法为测试相乘是否相等
assert lhs * rhs == exp_res
——test_mul_float
- 函数名为 test_mul_vec,即为测试相乘是否结果一致
- 出现了 lhs,rhs,exp_res 的初始化定义
- 故 LLM 可以判定方法为测试 Vector2D 与浮点数相乘的结果
assert lhs / rhs == exp_res
- 函数名为
test_div
,即测试除法 - 函数中对 lhs,rhs,exp_res 进行初始化
- 即 LLM 可以判定为测试除法是否正确
- 函数名为
assert abs(rhs) == lhs
- 函数名为
test_abs
,即测试绝对值 - 函数中对 reh 和 lhs 进行初始化
- 故可以判定方法为测试绝对值
- 函数名为
assert lhs != rhs
- 函数名为
test_equality_other_class
- 函数中定义了
lhs: Vector2D
和rhs: object
- 故 LLM 可知方法为测试两个不同类进行比较是否返回 False
- 函数名为
assert rhs < lhs
- 函数名为
test_less_than
- 初始化定义了两个 Vector2D 类 lhs 和 rhs
- 故 LLM 可知该断言应该为判断对象的小于比较是否正确
- 函数名为