如何提升单元测试的效率?

曾阅读过一个Java服务项目,单元测试的代码覆盖率非常高,但是没一个依赖方法验证,仅有几个数据对象断言。这些都是无效单元测试用例,根本起不到测试代码bug和回归验证代码的作用。

也见过之前有人提问,为什么要浪费写没有意义的单元测试。编写单元测试用例的目的,绝不是为了追求单元测试代码覆盖率,而是为了利用单元测试验证回归代码,尝试找出代码中潜藏的问题。

一、集成测试和单元测试的区别

单元测试是对程序的最小可测试部分进行测试,通常是对函数或方法进行测试。它们是独立的,不依赖于其他部分,并且快速执行。

集成测试则是对软件组件或系统中多个单元进行测试,以确保它们正确地协同工作。它们可能依赖于外部系统,如数据库或外部API,因此执行可能比单元测试慢得多。但它们可以更好地模拟实际使用情况,并可以捕获因组件间相互作用而导致的问题。

总的来说,单元测试和集成测试是相互补充的,通常需要同时使用,以确保软件的正确性和可靠性。

二、代码覆盖率是什么?

代码覆盖率是通过运行单元测试并记录哪些代码行被执行了,然后将其与总代码行数进行比较得出的。例如,如果代码中有100行,其中80行被测试到,那么代码覆盖率为80%。

代码覆盖率不是证明代码质量的完美指标,因为它不能保证所有代码都是正确的,也不能保证所有代码都被恰当地测试。但它是一个有用的工具,可以帮助开发人员确定未被测试的代码,并识别测试用例是否足够全面。

单元测试覆盖率只能代表被测代码的类、方法、执行语句、代码分直、条件子表达式等是否被执行,但是并不能代表这些代码是否正确地执行并返回了正确地结果。——所以之看单元测试覆盖率不看单元测试的有效性是没有任何意义得。

三、如何避免无效的单元测试

明确测试目的:在测试用例编写之前,确保它们是必要的并且能够有效地验证代码。比如要测试一个函数,它返回某个数组中最大值的索引,那么测试用例的目的就是验证该函数是否正确返回最大值的索引。

保持测试独立:单元测试应该是独立,不依赖于其他测试用例,也不依赖于外部环境。比如在测试某个函数时,可以确保不依赖于其他函数或任何外部状态。

关注代码边界:需要特别关注代码地边界情况,例如边界值、边界条件等。如果要测试一个数组排序函数,则应该特别关注边界情况,例如数组为空,数组只有一个元素等。

编写多种测试用例:编写多种不同类型的测试用例,以确保代码在不同情况下的正确性。在测试某个函数时,可以编写不同类型的测试用例,例如:测试输入数组为升序,降序和无序。

避免重复测试:避免编写重复的测试用例,以节省时间并保证测试用例的有效性。在测试一个数组排序函数时,不必测试两次同样的数组,只需测试一次即可。

跟踪代码变更:例如,如果更改了代码,则应定期更新测试用例,以确保它们仍然有效。

四、如何避免单元测试陷阱

假设我们有一个小函数可以做一件事,它被称之为calculate_average。我们可能会写一个测试test_calculate_average。然而更好地测试应该test_calculate_average_return_0_for_empty_list。

测试地重点应该是外部行为,如果过度关注内部行为,这时候实现逻辑进行了修改,那单元测试也就没有办法使用了。

跟踪测试覆盖率是一个衡量标准,但是100%代码覆盖率并不意味着我们已经覆盖了所有地边缘情况,下面是一个覆盖率100%的反面示例:

 
  1.   def average(elements: List[int]):

  2.     return sum(elements) / len(elements)

  3.   def test_average_returns_average_of_list:

  4.     result = average([1,3,5,7])

  5.     assert result == 4

所以应该集中在风险点上,使用打桩模拟和存根对于单元测试是必不可少的,但是要避免过度打桩。许多Mock模拟也是危险信号,当我们需要多个非常复杂的模拟来测试单个函数的时候,这个函数很可能复杂度过高。

对于数据一致性要求不高的系统,甚至可以直接对着接口进行测试,这样省去了编写Mock的复杂度。单元测试是为了保证代码质量,但是单元测试代码本身的质量也需要有一定保证,也就是尽可能简单。

还有很多情况,不一一写了。可以遵循单元测试的原则进行测试:

·单一责任原则:每个测试用例只测试一个功能,避免混杂多个功能的测试

· 快速执行原则:单元测试应该非常快,方便经常运行,避免因测试时间过长而导致开发人员不愿意运行测试

· 独立运行原则:单元测试应该独立运行,不应该相互依赖。每个测试都应该是可重复且独立的。

· 可重复性原则:单元测试应该具有可重复性,每次运行都应该产生相同的结果。

· 代码覆盖原则:单元测试应该覆盖每一个函数和代码路径,确保每一个函数都被测试了。

· 自动化原则:单元测试应该自动化,并且应该能够在每次代码提交后自动运行,确保不会因为遗漏而导致重大缺陷。

软件测试学习资料获取关注公众号:程序员雷叔    

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值