在不同语言中进行单元测试是否可接受?

28 投票
5 回答
5213 浏览
提问于 2025-04-18 06:22

我有一个用C++创建的静态库,现在想用驱动代码来测试它。

我注意到我的一个教授喜欢用Python来做测试,他通常会用随机的测试参数直接运行程序(在这种情况下不是库,而是可执行文件)。

我也想这样做,但我意识到这是一个库,没有主函数;这就意味着我需要创建一个Driver.cpp类,或者用SWIG或boost python把这个库封装成Python可以用的。

我打算选择后者,因为这样看起来更有趣,但从逻辑上讲,我觉得在把一个库封装成另一种语言来测试时,可能会出现更多的bug,而不是直接在它原本的语言中测试。

在现实中,用不同的语言测试程序是一种被接受的做法吗,还是说这样做不好?

5 个回答

4

我觉得这要看你到底想测试什么。如果是要进行真正的单元测试,我认为最好还是在同一种语言中测试,或者至少是在可以互相兼容的语言中测试(比如用Groovy来测试Java代码——我在这种情况下使用Spock,它是基于Groovy的,可以和Java代码混合使用)。不过,如果你是要测试结果,那么换语言也是可以的。

举个例子,我曾经在用Pythonnose工具测试一个Perl应用时,验证了给定一组特定数据时的预期结果。这是因为我并不是在单元测试Perl代码本身,而是在测试那段Perl代码的输出结果。

在这种情况下,如果我想要单元测试应用中实际的Perl函数,我会使用一个基于Perl的测试框架,比如Test::More

5

为什么不呢,这真是个好主意,因为你实际上是在像黑箱一样测试这个单元。

当然,可能会有一些技术问题,比如你需要模拟被测试单元的某些部分,这在不同的编程语言中可能会比较困难。

不过,这在集成测试中是很常见的做法,我见过很多程序是通过外部工具驱动的,比如用selenium从网站上测试,或者用cucumber从应用程序中测试。这两者都可以看作是自定义的python脚本。

如果你考虑集成测试和单元测试之间的区别,就是在任何时候测试的内容数量,那么唯一不应该这样做的原因就是工具的支持。

5

这其实要看你想测试的是什么。一般来说,写单元测试用和你测试的代码相同的语言是比较合理的,因为这样你可以更方便地创建测试对象或者调用测试函数,确保它们能正常工作。不过,也有一些情况适合用不同的语言,主要有以下两种:

  1. 集成测试,这种测试需要同时运行多个不同的组件或应用。

  2. 测试编译或解释错误,这种错误在原语言中无法测试,因为你是在验证语言层面是否出现了错误。

第一个例子的情况可能是一个程序,它启动多个相互连接的服务器,向这些服务器发出请求,并验证它们的响应。或者更简单的例子,就是一个程序,它将待测试的应用作为子进程启动,并验证在给定输入下是否能产生预期的输出。

第二个例子的情况可能是一个程序,用来验证某段C++代码是否会产生静态断言失败,或者某个特定的模板实例化如果被使用会导致编译失败,因为这个实例化是故意不被允许的。

回到你更大的问题,使用不同语言写测试本身并不是坏习惯。只要能让测试更方便写、更容易理解、更能适应实现的变化、更敏感于回归问题,或者在其他任何定义良好测试的特性上表现更好,都是合理的理由去选择不同的语言。如果这意味着要用另一种语言来写测试,那就去做吧。不过,通常情况下,小的单元测试需要直接调用待测试的项目,这在大多数情况下意味着单元测试要用和待测试组件相同的语言来写。

10

有几点需要记住:

  1. 如果你在编写代码的同时也在写测试,那就尽量使用最适合你的语言,这样可以快速得到反馈。这能让你快速循环测试和代码(而且也挺有趣的)。 但是

  2. 一定要用使用者的语言来编写好测试。你的客户或使用者是怎么调用你的函数的?他们会用什么语言?使用相同的语言可以减少后期整合时出现的问题。

29

我觉得最好是测试用户会接触到的API。其他的测试也很重要,但这是最关键的部分。

如果你的用户要写C/C++代码来链接你的库,那么最好有一些测试,能够像用户那样使用你的库。

如果你打算发布一个Python的封装(为什么不呢?),那么你应该有Python的测试。

当然,这里也有方便性的问题。用Python写测试可能更简单,而且你可能会面临时间限制,这样做会更吸引人等等。

我想我想表达的是:测试和被测试代码用不同语言并没有什么问题(比如测试REST API时,这种情况很正常),但至少要确保你有针对公开API的测试。


顺便说一下,关于术语:

我觉得你描述的测试类型在通常意义上并不是“单元测试”。“功能测试”可能更准确。

单元测试通常是测试一个非常小的组件,比如一个函数调用,这可能是更大功能的一部分。这种单元测试通常是“白盒”测试,你可以看到代码的内部工作原理。

从用户的角度测试某些东西(比如你教授的命令行测试)是“黑盒”测试,这些例子是在更功能层面,而不是“单元”层面。

不过,我相信很多人可能会不同意这一点——这些术语并不是严格定义的。

撰写回答