编写综合测试(附示例)
编写综合测试(附示例)
测试代码时,目标是确保无论将来发生什么变化,如果测试通过,我们就知道代码的行为与它应该表现的完全一致。我们应该以最少的测试次数为目标。
这是一般的想法。我将举一个例子以及如何找到它所需的测试用例。假设我们有这个功能:
定义除法(a,b):
"""a除以b,a和b可以是数字也可以是字符串,如果其中任何一个是字符串都将转换为数字。"""
如果类型(a)== str:
a = int(a)
如果类型(b)== str:
b = int(b)
返回 a / b
线路覆盖
需要多少个测试用例才能获得 100% 的线路覆盖率?我将一一列举:
断言除法(10, 2) == 5
这是最简单的测试。然而,线 a = int(a)
和 b = int(b)
不会被执行,这意味着在某些时候,有人会编辑它们(添加新功能或重构),我们不会自动知道它们是否有效,所以我们需要添加一个测试用例来覆盖这些行:
断言除法(“10”,“2”)== 5
声明覆盖范围
您还应该注意,有时一行中有多个语句,因此我们需要确保涵盖所有这些语句。例如,如果我们有这个功能:
定义除法(a,b):
# > 注意:你可能会说我们可以只做 `a = int(a)` 但这不是重点,把这个例子转换成你想要的任何东西
a = int(a) if type(a) == str else a
b = int(b) if type(b) == str else b
返回 a / b
如果我们只有这个测试:
断言除法(10, 2) == 5
然后将执行所有行,但不是所有语句,因此请记住这一点。
分支覆盖(或决策覆盖)
您通常不需要 100% 的分支覆盖率,但您需要牢记这一点,并决定添加覆盖额外分支的测试是否会增加价值。例如,假设我们有这个功能:
定义除法(a,b):
如果类型(a)== str:
# > 注意:您可能会说我们不应该这样做,但这只是一个示例,有时您的代码中会出现这种情况并且无法避免
a = int(a)
b = int(b)
返回 a / b
在这个函数中,我们有之前的两个测试:
断言除法(10, 2) == 5 断言除法(“10”,“2”)== 5
我们将拥有 100% 的行和 100% 的语句覆盖率,并且两个测试都将通过。但是,有一个输入会破坏代码,我们没有针对它进行测试,即:
断言除法(10,“2”)== 5
您需要做的是阅读代码并考虑代码中有多少分支以及测试更多分支是否有意义。
最大的问题
回到最初的例子:
定义除法(a,b):
如果类型(a)== str:
a = int(a)
如果类型(b)== str:
b = int(b)
返回 a / b
如果我们有这些测试:
断言除法(10, 2) == 5 断言除法(“10”,“2”)== 5
我们处于以下情况:
- 我们有 100% 的线路覆盖率
- 我们有 100% 的报表覆盖率
- 测试更多分支不会增加任何价值
这是全部吗?不幸的是没有。
我们需要问自己最大的问题: 有人可以在不导致测试失败的情况下更改我们的代码并破坏我们预期的行为吗?
如果答案是肯定的,我们必须添加一个测试来验证此行为是否按预期工作以使答案否定。
如果我们仔细观察,我们可以看到我们没有结果是浮点数的测试,这意味着如果有人编辑代码并更改 /
至 //
行为会中断,测试会通过,所以我们需要添加这个测试:
断言除法(10, 4) == 2.5
更多地方可以找到未经测试的行为
我们需要注意我们使用但未测试的代码(即,不包括在此函数的测试范围内)。我们需要确保我们只发送一个有效的输入并处理所有可能的输出。在此示例中,有两个示例:
- 这
整数()
功能 - 当我们做时将两个数字相除的函数
/
在蟒蛇
我们不需要知道这些函数的内部实现,因为我们不会对其进行测试。我们只想测试我们对它的使用,我们可以通过问自己这些问题来验证:
- 我们是否测试我们只提供允许的输入?
- 我们是否测试每种允许的输入?
- 我们是否测试我们处理所有可能的输出?
现在让我们使用第一个函数 整数()
并问自己三个问题:
- 我们是否测试我们只提供允许的输入?
在我们的代码中,我们只发送字符串到 整数()
,所以类型是正确的,但是该函数只接受表示数字的字符串,但我们正在向它发送任何字符串。我们应该问自己,将非数字字符串传递给函数是否应该被视为错误。如果它是一个错误,那么我们可以保持原样,不进行测试,但是如果我们认为它是错误的用户输入,那么我们需要:
- 在我们的代码中处理它。
- 记录行为。
- 为它添加一个测试。
2. 我们是否测试每种允许的输入?
那么包含浮点数的字符串呢?目前,我们的函数会引发异常,而我们的测试没有捕捉到它,所以我们需要编辑我们的代码以使用 漂浮()
函数代替 整数()
所以函数将是:
定义除法(a,b):
如果类型(a)== str:
一 = 浮动(一)
如果类型(b)== str:
b = 浮动(b)
返回 a / b
我们需要添加这个测试:
断言除法(“10.5”,“2”)== 5.25
3. 我们是否测试我们处理所有可能的输出?
在我们的例子中,这个函数总是返回相同的输出类型,所以没有什么好担心的,但我们需要检查一下。
你还应该问自己关于函数的三个相同的问题 /
.
如果我们错过了一个边缘案例怎么办?
如果我们在测试中遗漏了一个边缘案例,直到有人更改代码并破坏它,我们才会知道,然后当我们部署该破坏的更改时,只要我们的一个用户出现错误,我们就会收到警报,然后我们将修复错误。
但是,我们必须始终为我们发现的错误添加测试,这样随着时间的推移,我们将覆盖我们以前遇到的任何边缘情况。否则,我们将最终陷入这样一种情况,即我们有太多未经测试的边缘案例并且随时可能中断。
如果您想谈论我在这里写的任何内容,请随时与我们联系,我们可以进行更多讨论。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明