51Testing软件测试论坛
标题:
如何提升单元测试的效率?
[打印本页]
作者:
lsekfe
时间:
2023-4-14 10:56
标题:
如何提升单元测试的效率?
曾阅读过一个
Java
服务项目,
单元测试
的代码覆盖率非常高,但是没一个依赖方法验证,仅有几个数据对象断言。这些都是无效单元
测试用例
,根本起不到测试代码bug和回归验证代码的作用。
也见过之前有人提问,为什么要浪费写没有意义的单元测试。编写单元测试用例的目的,绝不是为了追求单元测试代码覆盖率,而是为了利用单元测试验证回归代码,尝试找出代码中潜藏的问题。
一、集成测试和单元测试的区别
单元测试是对程序的最小可测试部分进行测试,通常是对函数或方法进行测试。它们是独立的,不依赖于其他部分,并且快速执行。
集成测试则是对软件组件或系统中多个单元进行测试,以确保它们正确地协同工作。它们可能依赖于外部系统,如
数据库
或外部API,因此执行可能比单元测试慢得多。但它们可以更好地模拟实际使用情况,并可以捕获因组件间相互作用而导致的问题。
总的来说,单元测试和集成测试是相互补充的,通常需要同时使用,以确保软件的正确性和可靠性。
二、代码覆盖率是什么?
代码覆盖率是通过运行单元测试并
记录
哪些代码行被执行了,然后将其与总代码行数进行比较得出的。例如,如果代码中有100行,其中80行被测试到,那么代码覆盖率为80%。
代码覆盖率不是证明代码质量的完美指标,因为它不能保证所有代码都是正确的,也不能保证所有代码都被恰当地测试。但它是一个有用的工具,可以帮助开发人员确定未被测试的代码,并识别测试用例是否足够全面。
单元测试覆盖率只能代表被测代码的类、方法、执行语句、代码分直、条件子表达式等是否被执行,但是并不能代表这些代码是否正确地执行并返回了正确地结果。——所以之看单元测试覆盖率不看单元测试的有效性是没有任何意义得。
三、如何避免无效的单元测试
明确测试目的:
在测试用例编写之前,确保它们是必要的并且能够有效地验证代码。比如要测试一个函数,它返回某个数组中最大值的索引,那么测试用例的目的就是验证该函数是否正确返回最大值的索引。
保持测试独立:
单元测试应该是独立,不依赖于其他测试用例,也不依赖于外部环境。比如在测试某个函数时,可以确保不依赖于其他函数或任何外部状态。
关注代码边界:
需要特别关注代码地边界情况,例如边界值、边界条件等。如果要测试一个数组排序函数,则应该特别关注边界情况,例如数组为空,数组只有一个元素等。
编写多种测试用例:
编写多种不同类型的测试用例,以确保代码在不同情况下的正确性。在测试某个函数时,可以编写不同类型的测试用例,例如:测试输入数组为升序,降序和无序。
避免重复测试:
避免编写重复的测试用例,以节省时间并保证测试用例的有效性。在测试一个数组排序函数时,不必测试两次同样的数组,只需测试一次即可。
跟踪代码变更:
例如,如果更改了代码,则应定期更新测试用例,以确保它们仍然有效。
四、如何避免单元测试陷阱
假设我们有一个小函数可以做一件事,它被称之为calculate_average。我们可能会写一个测试test_calculate_average。然而更好地测试应该是是test_calculate_average_return_0_for_empty_list。
测试地重点应该是外部行为,如果过度关注内部行为,这时候实现逻辑进行了修改,那单元测试也就没有办法使用了。
跟踪测试覆盖率是一个衡量标准,但是100%代码覆盖率并不意味着我们已经覆盖了所有地边缘情况,下面是一个覆盖率100%的反面示例:
def average(elements: List[int]):
return sum(elements) / len(elements)
def test_average_returns_average_of_list:
result = average([1,3,5,7])
assert result == 4
所以应该集中在风险点上,使用打桩模拟和存根对于单元测试是必不可少的,但是要避免过度打桩。许多Mock模拟也是危险信号,当我们需要多个非常复杂的模拟来测试单个函数的时候,这个函数很可能复杂度过高。
对于数据一致性要求不高的系统,甚至可以直接对着接口进行测试,这样省去了编写Mock的复杂度。单元测试是为了保证代码质量,但是单元测试代码本身的质量也需要有一定保证,也就是尽可能简单。
还有很多情况,不一一写了。可以遵循单元测试的原则进行测试:
·
单一责任原则:每个测试用例只测试一个功能,避免混杂多个功能的测试
·
快速执行原则:单元测试应该非常快,方便经常运行,避免因测试时间过长而导致开发人员不愿意运行测试
·
独立运行原则:单元测试应该独立运行,不应该相互依赖。每个测试都应该是可重复且独立的。
·
可重复性原则:单元测试应该具有可重复性,每次运行都应该产生相同的结果。
·
代码覆盖原则:单元测试应该覆盖每一个函数和代码路径,确保每一个函数都被测试了。
·
自动化原则:单元测试应该自动化,并且应该能够在每次代码提交后自动运行,确保不会因为遗漏而导致重大缺陷。
以上。
欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/)
Powered by Discuz! X3.2