单元测试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

我会把这个留在这里几天,如果没有人反对,我会将其标记为我接受的答案!

编辑:我已经详细说明了,我在这里提出了另一个(已解决的)问题,只是稍作调整