我两三年前也遇到过类似的问题。我将一个设备驱动程序从VxWorks移植到Integrity。我们只改变了驱动程序的操作系统相关部分,但这是一个安全关键项目,所以所有单元测试和集成测试都需要重新进行。我们使用了一个名为LDRA testbed的自动化测试工具进行单元测试。我们的99%单元测试都在Windows机器上使用Microsoft编译器完成。现在我来解释一下如何做到这一点。
首先,当你进行单元测试时,你正在测试软件。当你将真实设备包含在测试中时,你还在测试设备。有时硬件或硬件文档可能存在问题。当你设计软件时,如果已经清楚地描述了每个函数的行为,那么进行单元测试就非常容易,例如考虑以下函数:
readMessageTime(int messageNo, int* time);
//This function calculates the message location, if the location is valid,
//it reads the time information
address=calculateMessageAddr(messageNo);
if(address!=NULL) {
read(address+TIME_OFFSET,time);
return success;
}
else {
return failure;
}
好的,这里你只是在测试readMessageTime是否按照预期工作。你不需要测试calculateMessageAddr是否计算出正确的结果,或者read是否读取了正确的地址。这是其他单元测试的责任。因此,你需要为calculateMessageAddr和read(OS函数)编写存根,并检查它是否使用正确的参数调用函数。如果您没有直接从驱动程序访问内存,则情况如此。您可以使用这种心态测试任何类型的驱动程序代码,而无需任何操作系统或设备。
如果您已将设备内存直接映射到内存空间中,并且设备驱动程序读取和写入设备内存,就像它自己的内存一样,那么情况会变得有些复杂。使用自动化测试工具,现在您必须观察指针的值,并根据这些指针的值定义通过/失败的标准。如果您正在从内存中读取值,则必须定义预期值。在某些情况下,这可能很困难。
还有一个问题,开发人员总是在驱动程序的单元测试中感到困惑,例如:
readMessageTime(int messageNo, int* time);
//This function calculates the message location, if the location is valid,
//it does some jobs to make the device ready to read then
//it reads the time information
address=calculateMessageAddr(messageNo);
if(address!=NULL) {
do_smoething(); // Get the device ready to read!
do_something_else() // do some other stuff so you can read the result in 3us.
status=NOT_READY;
while(status==NOT_READY) // mustn't be longer than 3us.
status=read(address+TIME_OFFSET,time);
return success;
} else
{
return failure;
}
这里的do_something和do_something_else是对设备进行一些操作,使其准备好读取。开发者们总是会问自己:“如果设备永远无法准备好,我的代码就会死锁”,因此他们倾向于在设备上测试这种情况。
那么,你必须相信设备制造商和技术作者。如果他们说设备将在1-2微秒内准备好,你就不需要担心这个问题。如果你的代码在这里失败了,你需要向设备制造商报告,而不是找到解决这个问题的方法。你明白我的意思吗?
希望这能帮到你……