单元测试C时如何重置状态机

How to reset state machines when unit testing C

本文关键字:何重置 状态机 单元测试      更新时间:2023-10-16

对于需要进行单元测试的TI处理器,我有一些嵌入式C
对于目标编译,使用了IAR,但我正在使用MinGW-GCC的Win7机器上运行测试。

在C代码中,有些包含状态机的函数有时需要在测试之间重置。这些状态机通常使其状态变量保持局部静态,即使不是不可能,也会使任务变得困难。

我不太懂C++类,但我有一个想法,把C函数"导入"到一个包装C++类中,作为成员函数,这样就可以在需要重置时创建一个新对象。下面的代码是不起作用的,但它说明了我的想法。

在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;
    }

在状态机中。h:

    void stateMachine(void);

在状态机中。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;
      }
      }
    }

不鼓励对状态机.c/.h进行更改,因为它可以被视为"遗留"
当然也欢迎任何其他解决方案!

包装没有帮助。C++代码无法到达用C.编写的状态机内的内部static变量

一种解决方案是对C部分使用动态代码加载,这将生成早期初始化代码并清除static变量。

您也可以将测试拆分为多个可执行文件,这具有相同的效果,但可能会产生更大的开销(=测试运行速度会更慢)。

@envel让我查看动态代码加载
阅读以下内容:从DLL动态加载函数,然后http://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/给了我足够的水来调制下面的溶液。

在状态机中。h:

    void stateMachine(void);

在状态机中。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();
    }

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

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

编辑:我已经详细阐述了一点,这里还有另一个(解决的)问题,我只需要稍微调整一下就可以导出一个函数,通过DLL 转换为指针