我们到底在测试什么?

2024-12-13   出处: everydayunittesting.com  作/译者:Gil Zilberfeld/Ares

每个单元测试的示例都从计算器开始,那么我们今天也这么做。来看一下这段代码。

public int add(int x, int y) {
    return x + y;
}

那么,你觉得我们需要多少测试用例来覆盖这段代码呢?

“覆盖”这个词其实相当模糊,是指“让你觉得可以放心发布你的代码的那些足够多的测试”吗?

我在我的研讨会(不仅仅是单元测试研讨会)上总是问这个问题。我得到了各种各样的答案,比如1+1,2+2,大数和负数,这些都是很好的情况。我们得出的结论是,人们觉得大概5-15个测试用例是合适的。

现在想想:这些真的是好的测试吗?它们到底在测试什么,它们有用吗?

这段代码是用Java写的(它可以是任何有“+”运算符的语言)。我们会为这个函数编写的每一个测试用例,包括我们上面提到的那些情况,实际上都是在测试“+”运算符的实现。

这并不令人惊讶,以下面为例:

return 1+1; 

真正执行计算的代码深藏在“+”运算符内部。实际上,它还涉及到隐式的“\=”运算符和一些内存操作。但我们可以称之为“加法计算”。

当我们添加两个非常大的数字时会发生什么?我们会得到一个异常,这个异常是由那些执行加法操作的家伙抛出的。我们也可以为这些情况编写测试用例,检查在正确的较大值下是否会抛出异常。

测试简单的东西也可能很复杂

所以,回到最初的问题:你需要多少测试用例才能感到放心?

测试工作应该是有用的,它们会在预期行为发生变化时告诉我们问题。那么这些测试会在什么情况下失败呢?

有几个选项。

在第一个选项中,如果我们(当然是不小心)替换了运算符,测试结果会告诉我们。例如,如果我们之前检查过4+2,现在会得到一个与之不同的结果。

public int add(int x, int y) {
    return x / y;
}

但我们谈论的是一个计算器,在这种代码中发生这种情况的可能性非常小。我们有很多提示告诉我们不要这样做。要像这样更改代码需要一定的……我们称之为“勇气”吧。

还有哪些选项会在测试中失败呢?

也许是“+”运算符中存在的一个错误?但是,这些运算符每天都在被全球数百万人使用。如果那里真的存在错误,我们可能早就听说了。

实际上,这些测试用例将永远通过,显然这些测试并不好。它们让我们产生了错误的信心,认为代码是有效的。对于从未见过失败的测试,我们的信任度会降低。那么,这对我们的其他测试有何影响呢?对某些测试的信任度降低意味着整体的质量信心也会下降。

让我们回到最初的问题。我们需要多少测试来覆盖那段代码?

也许答案是零,因为如果代码非常简单,我们可能根本不需要围绕它进行测试。当有人进入代码并进行修改,使其变得更复杂时,我们才会添加测试用例。这是为了防范开发人员引入新的复杂性问题。

如果我在进行TDD(测试驱动开发)呢?我会先编写测试用例,然后再编写开发代码,这意味着我最终可能只会得到一个测试场景。

同码异包

让我们来点更有意思的。现在,相同的代码不再在函数中运行,而是运行在一个API内部。

这是基于Spring框架的实现,用于执行一个POST操作,该操作将两个数字相加。

@PostMapping("/add")
public CalculationResult add(@RequestBody CalcRequest request) {
    int sum = request.getNumber1() + request.getNumber2();
    return new CalculationResult(sum);
}

我们是否坚持“几乎零测试”的答案?

一方面,代码是相同的。

但API测试不仅会运行我们的代码,还会运行大量的Spring代码。包括接收请求、返回响应、将JSON转换为对象等。更不用说那些未处理的异常了。

这次,除了我们的代码外,还有很多其他代码可能会导致测试失败。测试也可能因为配置问题而失败。例如,如果服务器没有运行,测试就会失败,但这与代码本身无关。

我们需要明白,问题的关键不在于“覆盖率”,而在于我们想从测试中了解到什么。

如果我们只对“我们的代码”感兴趣,那么我们就会回到之前的答案。但这次,这是有代价的。我们假设API测试的任何失败都与代码更改无关,因此不需要调试,也不需要重试。失败可以被忽略,测试只有在通过时才具有价值。

大多数人无法那样生活。

另一个选择是将测试视为验证一切的手段,包括我们的代码。如果测试失败,就意味着某个地方出了问题,我们需要花时间进行调试、查看日志或者修改配置,而这些工作可能根本没有任何价值。

不幸的是,大多数人却很好地适应了这样的生活方式。

在进行测试时,我们需要明白自己在测试什么,哪些因素会导致测试通过,哪些又会导致测试失败。

我们的测试是为了给我们提供信息而设计的。如果我们在编写测试用例之前没有考虑到这一点,那么我们编写的测试用例就不会那么有用,并且会在这些测试上浪费大量没有价值的时间。

我们应该知道自己在测试什么,以及希望从测试中得到什么。


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
19° /193 人阅读/0 条评论 发表评论

登录 后发表评论
最新文章