今天有很多人将单元测试作为发展的基础.这甚至可能适用于强大的面向算法的例程.但是,如何进行单元测试,例如内存分配器(想想malloc()/ realloc()/ free()).生成满足指定接口的工作(但绝对无用)的内存分配器并不难.但是如何提供绝对需要的单元测试功能的适当上下文,但不是合同的一部分:合并空闲块,在下一次分配时重用空闲块,将过多的空闲内存返回给系统,断言分配策略(例如第一次合适)真的受到尊重等
我的经验是断言,即使复杂和耗时(例如遍历整个空闲列表以检查不变量),工作要少得多,并且比单元测试更可靠,尤其是.编码复杂的,时间相关的算法.
有什么想法吗?
高度可测试的代码往往与其他代码的结构不同.
您描述了您希望分配器执行的几个任务:
合并自由块
在下次分配时重用空闲块
将多余的可用内存返回给系统
断言分配政策(例如先适合)确实得到尊重
虽然您可能会将分配代码编写为非常耦合,例如在一个函数体内执行其中的一些操作,但您也可以将每个任务分解为可测试块的代码.这几乎是你可能习惯的倒置.我发现可测试代码往往非常透明,并且由更小的部分构建.
接下来,我想说的是,在任何类型的自动化测试中,优于没有自动化测试.我肯定会更专注于确保你的测试做一些有用的事情而不是担心如果你正确使用了模拟,你是否确保它被正确隔离以及它是否是真正的单元测试.这些都是令人钦佩的目标,有望使99%的测试更好.另一方面,请使用常识和最佳工程判断来完成工作.
没有代码示例我不认为我可以更具体.
如果那里有任何逻辑,它可以进行单元测试.
如果您的逻辑涉及做出决策并调用OS /硬件/系统API,则伪造/模拟设备相关的调用并对您的逻辑进行单元测试,以验证是否在给定的一组前置条件下做出了正确的决策.在单元测试中遵循Arrange-Act-Assert三元组.
断言不能替代自动化单元测试.他们不告诉你哪个场景失败了,他们在开发过程中不提供反馈,他们不能用来证明代码满足所有规范.
非模糊更新: 我不知道确切的方法调用..我想我会'自己动手'让我们说你的代码检查当前条件,做出决定并根据需要调用操作系统.让我们说你的操作系统调用(你可能有更多):
void* AllocateMemory(int size); bool FreeMemory(void* handle); int MemoryAvailable();
首先将其转换为界面,I_OS_MemoryFacade
.创建此接口的实现以实际调用OS.现在让你的代码使用这个接口 - 你现在已经将你的代码/逻辑与设备/操作系统分离.接下来在你的单元测试中,你使用一个模拟框架(它的目的是为你提供一个指定接口的模拟实现.然后你可以告诉模拟框架,期望这些调用,使用这些参数,并在它们是时返回在测试结束时,您可以要求模拟框架验证是否满足所有期望.(例如,在此测试中,AllocateMemory应被调用三次,10,30,50作为参数,然后是3个FreeMemory调用.如果MemoryAvailable返回初始值.)
由于您的代码依赖于接口,因此它不知道实际实现与您用于测试的伪/模拟实现之间的区别.Google提供了"模拟框架"以获取更多相关信息.