【问题标题】:How to reset state machines when unit testing C单元测试C时如何重置状态机
【发布时间】:2016-02-04 19:06:01
【问题描述】:

我有一组用于 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;
    }

在 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 进行更改,因为它可以被视为“遗留”。
当然也欢迎任何其他解决方案!

【问题讨论】:

    标签: c++ c unit-testing state-machine


    【解决方案1】:

    包装没有用。 C++ 代码无法访问用 C 编写的状态机内部的内部 static 变量。

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

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

    【讨论】:

    • 我希望实现的不是访问static 变量,而是一种创建新的状态机实例的方法。是的,我想到了多个执行者的方式,但正如你所说,与仅在新对象上执行另一次运行相比,这需要大量的额外时间。
    • @Enok82 但是这种 C 代码没有“实例”的概念。全局变量永远是全局变量。它将由启动代码初始化(在main() 在正常程序中运行之前),以后无法再次调用。
    • 成功...您指向动态代码加载的指针使我走上了一条通往非常有用的道路。我会在一两分钟内在这里发布我的解决方案!谢谢!
    【解决方案2】:

    @unwind 让我查看动态代码加载!
    阅读这些: Dynamically load a function from a DLLhttp://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
    

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

    编辑:我已经详细说明了一点,我这里还有另一个(已解决的)问题,只需稍作调整Exporting a function, cast into a pointer through a DLL

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多