单元测试C时如何重置状态机
How to reset state machines when unit testing C
我有一套用于 TI 处理器的嵌入式 C,需要进行单元测试。
对于目标编译,使用了 IAR,但我 运行 使用 MinGW GCC 在 Win7 机器上进行测试。
在 C 代码中,有些函数包含有时需要在测试之间重置的状态机。这些状态机通常将它们的状态变量保持在局部静态,即使不是不可能,也使该任务变得困难。
我不是很懂 C++ class 但我有一个想法 "importing" 将 C 函数封装到一个包装 C++ class 中作为成员函数,这样就可以创建一个新的每当我需要重置时对象。下面的代码不起作用,但它说明了我的想法。
在main.cpp中:
#include "statemachine.h"
using namespace std;
class stateMachineWrapper {
public:
extern void stateMachine(void);
};
int main() {
stateMachineWrapper myObject;
myObject.stateMachine();
myObject.stateMachine();
stateMachineWrapper myNewObject;
myNewObject.stateMachine();
myNewObject.stateMachine();
return 0;
}
在statemachine.h中:
void stateMachine(void);
在statemachine.c中:
#include <stdio.h>
void stateMachine(void)
{
static int myState = 0;
switch(myState)
{
case 0:
{
printf("Init State");
myState = 1;
break;
}
case 1:
{
printf("Second state");
break;
}
default:
{
printf("Default");
break;
}
}
}
不鼓励对 statemachine.c/.h 进行更改,因为它可以被视为 "legacy".
当然也欢迎任何其他解决方案!
包装无济于事。 C++ 代码无法访问用 C 语言编写的状态机中的内部 static
变量。
一种解决方案是对 C 部分使用动态代码加载,这将生成早期初始化代码并清除 static
变量。
您也可以将测试拆分为多个可执行文件,这具有相同的效果,但可能会产生更大的开销(=测试会 运行 更慢)。
@unwind 让我查看动态代码加载!
阅读这些:
Dynamically load a function from a DLL and http://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/ 足以让我制定以下解决方案。
在statemachine.h中:
void stateMachine(void);
在statemachine.c中:
#include <stdio.h>
void stateMachine(void)
{
static int myState = 0;
switch(myState)
{
case 0:
{
printf("Init State");
myState = 1;
break;
}
case 1:
{
printf("Second state");
break;
}
default:
{
printf("Default");
break;
}
}
}
在statemachinelib.c中:
#include "statemachine.h"
__declspec(dllexport) void __cdecl statemachineWrap()
{
stateMachine();
}
在main.c中:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
typedef int (__stdcall *f_funci)();
int main(int argc, char **argv)
{
HINSTANCE hGetProcIDDLL = LoadLibrary("statemachinelib.dll");
f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "statemachineWrap");
funci();
funci();
funci();
FreeLibrary(hGetProcIDDLL); //Windows detects that no one is using this library anymore and unloads it from memory, giving the new LoadLibrary a fresh instance
hGetProcIDDLL = LoadLibrary("statemachinelib.dll");
funci = (f_funci)GetProcAddress(hGetProcIDDLL, "statemachineWrap");
funci();
funci();
funci();
return 0;
}
在这段代码中,我省略了很多安全声明,例如检查是否可以加载 DLL,是否找到函数,是否需要 dllexport 或 dllimport 等等,只是为了更容易掌握什么正在进行。如果您打算在任何实际项目中实现它,您至少应该阅读我上面提到的两个资源。
使用 MinGW 编译 DLL:
>gcc -c statemachine.c statemachinelib.c
>gcc -o statemachinelib.dll -s -shared statemachinelib.o statemachine.o -Wl,--subsystem,windows
可执行文件的编译,也是 MinGW:
>gcc -o main.exe main.c
执行收益:
>main.exe
Init State
Second state
Second state
Init State
Second state
Second state
我会把这个留在这里几天,如果没有人反对,我会将其标记为我接受的答案!
编辑:我已经详细说明了,我在这里提出了另一个(已解决的)问题,只是稍作调整
我有一套用于 TI 处理器的嵌入式 C,需要进行单元测试。
对于目标编译,使用了 IAR,但我 运行 使用 MinGW GCC 在 Win7 机器上进行测试。
在 C 代码中,有些函数包含有时需要在测试之间重置的状态机。这些状态机通常将它们的状态变量保持在局部静态,即使不是不可能,也使该任务变得困难。
我不是很懂 C++ class 但我有一个想法 "importing" 将 C 函数封装到一个包装 C++ class 中作为成员函数,这样就可以创建一个新的每当我需要重置时对象。下面的代码不起作用,但它说明了我的想法。
在main.cpp中:
#include "statemachine.h"
using namespace std;
class stateMachineWrapper {
public:
extern void stateMachine(void);
};
int main() {
stateMachineWrapper myObject;
myObject.stateMachine();
myObject.stateMachine();
stateMachineWrapper myNewObject;
myNewObject.stateMachine();
myNewObject.stateMachine();
return 0;
}
在statemachine.h中:
void stateMachine(void);
在statemachine.c中:
#include <stdio.h>
void stateMachine(void)
{
static int myState = 0;
switch(myState)
{
case 0:
{
printf("Init State");
myState = 1;
break;
}
case 1:
{
printf("Second state");
break;
}
default:
{
printf("Default");
break;
}
}
}
不鼓励对 statemachine.c/.h 进行更改,因为它可以被视为 "legacy".
当然也欢迎任何其他解决方案!
包装无济于事。 C++ 代码无法访问用 C 语言编写的状态机中的内部 static
变量。
一种解决方案是对 C 部分使用动态代码加载,这将生成早期初始化代码并清除 static
变量。
您也可以将测试拆分为多个可执行文件,这具有相同的效果,但可能会产生更大的开销(=测试会 运行 更慢)。
@unwind 让我查看动态代码加载!
阅读这些:
Dynamically load a function from a DLL and http://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/ 足以让我制定以下解决方案。
在statemachine.h中:
void stateMachine(void);
在statemachine.c中:
#include <stdio.h>
void stateMachine(void)
{
static int myState = 0;
switch(myState)
{
case 0:
{
printf("Init State");
myState = 1;
break;
}
case 1:
{
printf("Second state");
break;
}
default:
{
printf("Default");
break;
}
}
}
在statemachinelib.c中:
#include "statemachine.h"
__declspec(dllexport) void __cdecl statemachineWrap()
{
stateMachine();
}
在main.c中:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
typedef int (__stdcall *f_funci)();
int main(int argc, char **argv)
{
HINSTANCE hGetProcIDDLL = LoadLibrary("statemachinelib.dll");
f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "statemachineWrap");
funci();
funci();
funci();
FreeLibrary(hGetProcIDDLL); //Windows detects that no one is using this library anymore and unloads it from memory, giving the new LoadLibrary a fresh instance
hGetProcIDDLL = LoadLibrary("statemachinelib.dll");
funci = (f_funci)GetProcAddress(hGetProcIDDLL, "statemachineWrap");
funci();
funci();
funci();
return 0;
}
在这段代码中,我省略了很多安全声明,例如检查是否可以加载 DLL,是否找到函数,是否需要 dllexport 或 dllimport 等等,只是为了更容易掌握什么正在进行。如果您打算在任何实际项目中实现它,您至少应该阅读我上面提到的两个资源。
使用 MinGW 编译 DLL:
>gcc -c statemachine.c statemachinelib.c
>gcc -o statemachinelib.dll -s -shared statemachinelib.o statemachine.o -Wl,--subsystem,windows
可执行文件的编译,也是 MinGW:
>gcc -o main.exe main.c
执行收益:
>main.exe
Init State
Second state
Second state
Init State
Second state
Second state
我会把这个留在这里几天,如果没有人反对,我会将其标记为我接受的答案!
编辑:我已经详细说明了,我在这里提出了另一个(已解决的)问题,只是稍作调整