什么是黑匣子单元测试?


11

我最近完成了针对硕士课程的软件工程课程的期末考试,该考试中的一个问题如下:

Unit Testing is considered:
a. White-box Testing
b. Black-box Testing
c. Either

在我7年的软件开发经验中,单元测试始终采用白盒方法。测试人员在编写测试时始终对单元的实施有充分的了解。黑盒测试总是以集成,系统和验收测试的形式出现。

但是,对考试的正确答案(根据教授的说法)是单元测试可以是白盒测试或黑盒测试。

我已经进行了一些研究,似乎很多情况下都使用“黑盒单元测试”来描述一种先测试的方法,即在代码之前编写单元测试。但是我认为这仍是白盒测试。尽管实现尚不存在,但是编写测试的人通常都对如何实现源代码有一个很好的了解。

有人可以告诉我黑匣子单元测试的工作原理(如果确实如此),以及它与白匣子单元测试有何不同?


4
当您问他们这个问题时,教授是如何澄清的?(另请参见为什么面试问题会使软件Engineering.SE问题变得很糟糕?
t

“编写测试的人通常对如何实现测试都有一个很好的主意”-这不是关于您是否知道测试的实现方式,而是您是否知道(白色)或(黑色)事情如何您正在执行的测试
Jesper

@Jesper对不起。我的意思是说“如何实现源代码”。我已经解决了这个问题。
backcab

2
While the implementation does not yet exist, whoever is writing the test generally has a pretty good idea about how the source code is going to be implemented.-是的,但是测试本身没有。 白盒测试意味着测试方法或类内部的某些内容,例如变量的值。这并不意味着测试编写者知道被测代码的样子。
罗伯特·哈维

Answers:


20

您的教授是对的:单元测试可以是黑盒或白盒。区别不在于测试人员所了解的内容,而在于您如何生成测试用例。

使用黑匣子测试,您只需查看接口和组件规范(如果存在)。当一个函数具有签名时int foo(int a, int b),我可以通过测试有趣的整数立即生成一些测试用例:零,一,减一,多位数,INT_MAX,INT_MAX-1等。黑盒测试非常棒,因为它们独立于实现。但是他们也可能错过重要案例。

通过白盒测试,我将研究实现,即源代码,并从中生成测试用例。例如,我可能想实现某个功能的100%路径覆盖率。然后,我选择输入值,以便采用所有路径。白盒测试非常棒,因为它们可以穷举地执行一段代码,比黑盒测试更有信心。但是它们可能只是测试实现细节,而不是实际上重要的行为。在某些情况下,它们显然是浪费时间。

由于白盒测试是从实现中派生的,因此只能在以后编写。黑盒测试源自设计/接口/规范,因此可以在实现之前或之后编写。TDD既不是黑盒子也不是白盒子。由于所有行为都首先由测试表示,然后实现该行为的最少代码,因此TDD产生的测试用例与白盒测试类似。但是,当我们查看信息流时,TDD测试并非源自源代码,而是源自外部需求。因此,TDD更像黑​​盒。


3
“因为白盒测试是从实现派生的,所以只能在以后编写” -好吧,如果我要为下一个新功能编写TDD风格的失败测试,​​我想将其添加到现有函数或类中,我首先研究当前的实现以了解到目前为止尚不支持的功能,因此我可以设计一个更有意义的(最初是失败的)测试。我将其称为“测试优先白盒”方法,而不是随后编写的测试。(不过,我是+1)。
布朗

4

如果您要进行测试驱动开发,那么从理论上讲,您所有的单元测试都应该是黑盒。这是您的“测试优先方法”。您编写合同(接口),编写该合同的测试,然后实现即可满足合同要求。因此,测试对实现一无所知,也不应该一无所知。

毕竟,当您编写测试时,您正在测试什么?公共方法/功能。

如果您要为某个班级编写接口,然后编写测试,然后被公交车撞到,那么在住院期间编写班级的人应该可以从您的界面中这样做,对吗?他不必扔掉它并编写自己的界面和测试。

当您需要模拟实现所依赖的内容时,这种情况会有所区别,但是如果您发现自己正在嘲笑从未公开的东西,那么您就犯了一个错误,并且您需要期待依赖注入。因此,我认为白盒单元测试而不是黑盒测试应该是例外。

考虑“在马桶上测试-测试行为而非实现”,其中更改了类的实现,但测试仍应有效。

但是,如果您需要确保代码覆盖范围足够(即,确保在实现中测试了所有条件路径),则绝对需要对单元测试进行白盒测试,因为只有这样,您才能知道路径是通过查看实现中的路径。


2
If you were to write the interface for a class, and then write the tests, and then you get hit by a bus, the guy who writes the class while you're in hospital should be able to do so from your interface, right? - 不完全是。大多数API合同只真正指定方法签名,而不指定语义或行为。
罗伯特·哈维

你是对的; 我认为您的接口将包括编写接口的规范,而不仅仅是MyClassInterface的文本。
AdamJS '17

@RobertHarvey的确,大多数接口都没有明确描述语义或行为,但我认为它通常是隐式存在的。如果不存在,则需要某些语义的代码将无法依赖抽象。而且没有什么可以停止接口的了,包括语义和行为的详细信息,如comment / docblocs。例如,请参见github.com/php-fig/http-message/blob/master/src/…–
bdsl

3

我认为所有写得很好的单元测试本质上都是“黑匣子”。当然,编写测试时可能会想到一个实现,但是重构时该实现可能会改变。因此,在测试过程中,测试仅应使用公共API来测试功能,而不是实现。它不在乎实现细节,因此进行了黑盒测试。

如果编写用于访问被测单元内部或私有方面的测试,那么我正在测试实现细节:我是白盒测试。但是我也在写易碎的测试,当实现更改时,它很容易中断。因此,这种白盒测试不是一个好主意,应该避免。

结论:如果您将白盒测试与单元测试结合使用,则您的测试结构较差。只有底盒测试和那些单元测试。您的教授是正确的:可以。但只有做得不好。


1

我只是在编写执行黑盒测试的单元测试的过程中。也就是说,我正在测试一个类中的公共方法,并将结果测试逻辑包含在它们调用的私有方法中。

我通过将输入更改为要进行单元测试的公共方法,并测试由逻辑支持的私有方法确定或变异的预期输出来实现,我的“单元测试”的实现不需要任何知识。

因此,没有什么可以阻止您对单元测试执行黑盒测试,并且如果有人对隐藏的支持逻辑的实现感到困惑,则测试会中断。实际上,与白盒单元测试类中的所有内容相比,这似乎是一种更好,更有效的方法。我和教授在一起。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.