如何在C中进行依赖注入?

Dou*_*oug 19 c dependency-injection

我正在寻找一个在C中进行DI的良好技术解决方案.

我已经在这里看到了一些DI问题,但我没有看到任何实际的例子或具体的实施建议.

所以,假设我们有以下情况:

我们在c中有一组模块; 我们想重构这些模块,以便我们可以使用DI来运行单元测试等等.

每个模块实际上由一组c函数组成:

module_function(...);

模块相互依赖.IE浏览器.通常,您可能会打电话,例如:

int module1_doit(int x) {
  int y = module2_dosomethingelse(x);
  y += 2;
  return(y);
}
Run Code Online (Sandbox Code Playgroud)

DI的正确方法是什么?

可能的解决方案似乎是:

  • (1)为所有模块函数使用函数指针,并在调用函数时执行此(或类似):

    int y = modules-> module2-> dosomethingelse(x);

  • (2)使用相同的符号编译多个库(mock,std等),并在正确的实现中动态链接.

(2)似乎是正确的方法,但是很难配置并且烦人地迫使你为每个单元测试构建多个二进制文件.

(1)似乎它可能会起作用,但在某些时候你的DI控制器会陷入需要动态调用通用工厂函数(void ( factory)(...)说)的情况下需要在运行时注入的其他模块?

在c中还有另一种更好的方法吗?

这样做的"正确"方法是什么?

小智 10

我没有看到在C中使用DI有任何问题.请参阅:

http://devmethodologies.blogspot.com/2012/07/dependency-injection.html


djs*_*djs 9

我得出的结论是,在C语言中没有"正确"的方法.与其他语言相比,它总是比较困难和繁琐.但是,我认为重要的是,不要为了单元测试而混淆代码.将所有内容都设置为C中的函数指针可能听起来不错,但我认为它最终会让代码变得可怕.

我最近的方法是保持简单.我不会更改C模块中的任何代码,除了#ifdef UNIT_TESTING文件顶部的一小部分用于外部和内存分配跟踪.然后我接受模块并编译它,删除所有依赖项,以便它失败链接.一旦我查看了未解析的符号以确保它们是我想要的,我运行一个脚本来解析这些依赖项并为所有符号生成存根原型.这些都被转储到单元测试文件中.YMMV取决于外部依赖项的复杂程度.

如果我需要在一个实例中模拟一个依赖项,在另一个实例中使用真实的,或者在另一个实例中使用它,那么我最终会为一个被测模块提供三个单元测试模块.拥有多个二进制文件可能并不理想,但它是C的唯一真正选项.但它们都可以同时运行,所以对我来说这不是一个真正的问题.


ssf*_*frr 9

这是Ceedling的完美用例.

Ceedling是一个整合伞形项目,它将Unity和CMock(以及其他东西)结合在一起,它们可以自动完成您所描述的大量工作.

通常,Ceedling/Unity/CMock是一组ruby脚本,它们扫描您的代码并根据您的模块头文件自动生成模拟,以及测试运行器,它们可以找到所有测试并生成将运行它们的运行程序.

为每个测试套件生成一个单独的测试运行器二进制文件,在您的测试套件实现中按照您的请求链接相应的模拟和实际实现.

我最初犹豫是否将ruby作为依赖我们的构建系统进行测试,它似乎有很多复杂性和魔力,但在尝试完并使用自动生成的模拟代码编写一些测试后,我被迷住了.