如何在 C 中的同一个 UUT 中模拟函数

How to mock function in same UUT in C

我正在学习使用 Ceedling 进行单元测试,在现有的嵌入式 C 代码库(我可以对其进行调整以适应)上使用 CMock 进行模拟。

我遇到过单元中的一个函数调用同一单元中的第二个函数的情况。

int foo_a(int r) 
{
    /* foo_a work */
    /* do not wish to test this function just to test foo_b. */
}

int foo_b(int i) /* function to test */
{
    /* foo_b work */
    if (some_condition)
        foo_a(k); /* need to test if foo_a() is called or not. */
}

我不想将 foo_a() 作为 foo_b() 测试的一部分进行测试。我如何模拟 foo_a() 以便我仍然可以测试它是否被调用但不测试 foo_a() 函数本身?

如果不修改您的源代码,您将无法执行此操作。

考虑将函数分解为两个单独的编译单元。

或者,在要替换的函数周围添加一个 #ifndef TEST

根据我使用 ceedling 的经验,最好的方法是创建自定义 TEST_ASSERT_FOO_A_IS_CALLED(); 或者,细微差别,TEST_ASSERT_IS_DOING_WHAT_FOO_A_SHOULD_BE_DOING(); 在第二种情况下,您正在测试是否正在执行某些操作集,而不是您不应该知道的内部函数。

理论上,使用单元测试您不关心该函数如何运行(即您不关心 foo_b() 是否调用 foo_a(),只要 foo_b() 做同样的事情模拟函数为 foo_a() ),你不应该能够判断是否调用了内部(私有)函数,例如 foo_a() 。因此,您应该测试是否正在调用模拟函数,而不是内部函数本身。

如何创建自定义 ASSERT? 很简单,只需使用普通的 C 宏定义它,例如:

#define TEST_ASSERT_FOO_A_IS_CALLED() \
{                                     \
  TEST_ASSERT_CALLED(some_mocked_function_foo_a_is_expected_to_call);                              \
  TEST_ASSERT_EQUAL_MESSAGE(expected_value, some_mocked_function_foo_a_is_expected_to_call_fake.arg0_val, "Something wrong with arg0!"); \
}

包含“_MESSAGE”断言不是必需的,但更容易发现宏中的哪个断言失败了,因为宏中的每个 'fail' 都将显示相同的行号,这使得更难发现它。

如果由于某种原因这种情况经常发生,这表明 foo_a() 应该在另一个可以模拟的源文件中。