Linux 内核中的单元测试
Brendan Higgins 最近提议向 Linux 内核添加单元测试,以补充其他开发基础设施,如 perf、autotest 和 kselftest。测试的整个问题对于内核开发者来说非常重要,因为 Linux 位于系统的核心,并且通常具有非常强的稳定性/安全性要求。大量的自动化测试定期检查内核源代码,并将任何异常情况报告给邮件列表。
Brendan 说,单元测试专门用于测试独立的代码片段。为了执行单元测试,没有必要运行整个内核,甚至编译内核源代码树。要测试的代码可以完全从树中提取出来并独立测试。他解释说,除其他好处外,这意味着可以在不到一秒钟的时间内执行数十个单元测试。
为了表示应有的敬意,Brendan 指出 JUnit、Python 的 unittest.mock 和 C++ 的 Googletest/Googlemock 是这个新的 KUnit 测试想法的灵感来源。
Brendan 还指出,由于所有被单元测试的代码都是独立的并且没有依赖项,这意味着测试也是确定性的。与运行中的 Linux 系统不同,在运行中的 Linux 系统中,运行系统的任何部分都可能导致给定问题,单元测试将以可重复的确定性识别问题代码。
Daniel Vetter 对 Brendan 的工作做出了非常热情的回复。他特别指出,“拥有用于内核单元测试的适当且标准化的基础设施听起来太棒了。换句话说:我想要。” 他补充说,他和其他人已经在为 Direct Rendering Manager (DRM) 驱动程序开发一套更加专业的单元测试。他说,Brendan 的方法将比他自己更本地化的努力方便得多。
Dan Williams 也对 Brendan 的工作感到非常兴奋,他说他一直在 libnvdimm(非易失性设备)项目代码上进行半吊子的单元测试。他认为 Brendan 的工作更通用,并且他想将自己的测试转换为使用 KUnit。
Tim Bird 也回复了 Brendan 的初始电子邮件,他说他认为单元测试可能很有用,但他想确保行为是正确的。他特别希望澄清如何测试独立的代码。如果要独立编译代码,那么它会在本地系统上运行吗?如果本地系统与代码 intended 的系统具有不同的硬件架构怎么办?此外,谁将维护单元测试,测试将位于源代码树中的什么位置?它们会使被测试的目录变得混乱,还是会远离居住在专门为测试代码保留的目录中?最后,测试代码会比被测试的代码更容易编写吗?换句话说,新开发人员可以通过编写测试代码来磨练项目,以此作为帮助处理给定驱动程序或子系统的入门途径吗?或者单元测试是否必须由已经完全精通该领域的人员编写?
Brendan 试图依次解决所有这些问题。首先,他确认测试代码确实是在本地系统上提取和编译的。他说,最终,每个测试都将编译成自己完全独立的测试二进制文件,尽管目前,它们都集中在一个 用户模式 Linux (UML) 二进制文件中。
在为其他架构交叉编译测试代码方面,Brendan 认为这将很难维护,并决定不支持它。测试将在本地运行,并且不依赖于特定于架构的特性。
在单元测试的存放位置方面,Brendan 说它们将与被测试的代码位于同一目录中。因此,每个目录都将拥有自己的一组随时可用且可见的单元测试。维护被测试代码的同一个人将维护测试本身。本质上,单元测试将成为每个项目的附加元素。然后,该维护者大概会要求对该驱动程序或子系统的所有补丁都通过所有单元测试,然后才能被接受到树中。
在谁有资格为给定项目编写单元测试方面,Brendan 解释说:
为了编写单元测试,编写测试的人员必须了解他们正在测试的代码应该做什么。在某种程度上,这可能需要一些具有一定专业知识的人员来确保测试有意义,实际上,破坏测试的更改应该附带测试的更新。另一方面,我认为理解预先存在的代码的作用和应该做什么比从头开始编写新代码容易得多,并且可能不需要太多的专业知识。
Brendan 补充说,单元测试可能会减少而不是增加维护人员的工作量。尽管总体上代表了更多的代码:
带有单元测试的代码通常更简洁,测试告诉我代码应该做什么,我可以运行测试(或理想情况下让自动化服务运行测试),告诉我代码实际上做了测试所说的应该做的事情。即使在编写代码时,我也发现编写带有单元测试的代码最终会节省我的时间。
总的来说,Brendan 对所有积极的兴趣感到非常高兴,并表示他计划发布更多版本来解决讨论过程中出现的各种技术建议。实际上没有人提出反对 Brendan 任何想法的声音。单元测试似乎很快将成为许多驱动程序和子系统的标准组成部分。
注意:如果您在上面被提及并想在评论区上方发布回复,请将您的回复文本发送消息至 ljeditor@linuxjournal.com。