【问题标题】:C unit test: stubbing fread/fwrite functionsC 单元测试:存根 fread/fwrite 函数
【发布时间】:2012-01-22 23:45:00
【问题描述】:

我开始用 C 编写一个小程序作为开发练习,我希望对这个程序进行大量单元测试。问题是它有时会使用 fread/fwrite 和其他标准函数——我不希望我的单元测试打开任何文件,所以如果我可以为 fread/fwrite 编写存根就好了。

谁有解决这个问题的办法?

提前感谢您的回答!

编辑:我忘记了一件重要的事情:用于读取的存根需要在不同的测试中表现不同。一方面,读取的返回值必须是

【问题讨论】:

    标签: c unit-testing stub


    【解决方案1】:

    有多种选择:

    1. 通过函数指针将fopen()fread() 等转换为间接函数调用。对于正常操作,将它们设置为指向fopen() 等。对于测试,将它们设置为指向您的函数。
    2. 定义你的替换函数myfopen()myfread()等。用名为fopenfread等的宏编译程序的主要部分并扩展为myfopenmyfread等。
    3. 定义您自己的fopen()fread() 等。使用链接器让它们替换标准库中的链接器。这非常容易出错并且很难做到。
    4. 使用反汇编、汇编和运行时代码修补来挂钩fopen()fread() 等函数。这也不容易。

    【讨论】:

      【解决方案2】:

      我可以推荐Working Effectively with Legacy Code 这本书,因为它在许多章节中都涉及到这个问题。我自己也用过类似的情况。

      对于过程语言中的单元测试有两个建议(除了转换为面向对象的语言):

      • 使用“链接器接缝”。在 API 调用周围使用包装器函数,并根据您是编译测试还是可交付成果使用不同的目标文件进行编译。测试版本将在包装函数内部存根调用,而发布代码版本会将调用传递给 fread、fwrite 等。
      • 使用“预处理接缝”,您可以在其中使用 #ifdefs 通过在特定于测试的 #ifdef 下定义本地版本或使用更易于维护的包装函数选项来更改 fread/fwrite/etc 的行为(再次)根据是否定义了特定于测试的 #ifdef 来改变行为。

      【讨论】:

        【解决方案3】:

        如果我正确理解了这个问题,最简单的方法是使用宏(跳过讨论它的邪恶):

        #ifdef UNIT_TESTS
            #define fwrite(ptr, size, nmemb, stream) (nmemb)
        #endif
        

        fread 也一样。现在,您可以在使用单元测试进行编译时使用编译器标志指定宏 UNIT_TESTS(如 gcc 的 gcc -DUNIT_TESTS ...)。

        【讨论】:

        • 这将导致实际检查返回值的程序失败。 .... 下一个!。
        • 这里看不出有什么问题,就#define fwrite(ptr, size, nmemb, stream) ((nmemb) * (size))
        • 更错了。 fread() /fwrite() 返回 items 的数量,而不是字符数。
        【解决方案4】:

        我也会使用宏。

        创建一个文件:

        #define fopen FOPEN
        #define fread FREAD
        #define fwrite FWRITE
        

        然后将其添加为强制包含,使其在所有其他包含之前进入。

        然后你可以在你的存根代码中实现 FOPEN 来做任何你想做的事情。

        【讨论】:

          猜你喜欢
          • 2020-12-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-29
          • 2021-07-27
          • 2012-03-06
          • 2023-03-03
          • 1970-01-01
          相关资源
          最近更新 更多