如何在 C 中模拟同一 UUT 中的函数
Posted
技术标签:
【中文标题】如何在 C 中模拟同一 UUT 中的函数【英文标题】:How to mock function in same UUT in C 【发布时间】:2016-11-08 11:32:29 【问题描述】:我正在学习在现有的嵌入式 C 代码库(我可以调整以适应)上使用 Ceedling 和 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()
函数本身?
【问题讨论】:
我对 C 了解不多,但如果它与许多其他语言一样,可以将方法标记为虚拟/可覆盖。在这种情况下,您可以提供一个已知/设置返回为foo_a
的模拟/伪造。这样,在使用模拟/假类时,当 you.call foo_b
时,您将使用 foo_a
的模拟/覆盖方法而不是真正的 impl,因此您可以专注于测试 foo_b
而不必担心 @987654330 @impl。
@kritner C 不是面向对象的。它没有虚拟、可覆盖、继承或多态等概念。
【参考方案1】:
如果不修改源代码,您将无法做到这一点。
考虑将函数拆分为两个独立的编译单元。
或者,在要替换的函数周围添加#ifndef TEST
。
【讨论】:
这让我可以引入一个假货,但我如何确定假货是否被调用?首先的想法是简单地引入一个全局标志,如果调用了假,则设置该标志,然后在我的测试中检查该标志。有没有更好的方法或更推荐的做法?【参考方案2】:根据我使用 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”断言不是必需的,但更容易发现宏中的哪个断言失败,因为宏中的每个“失败”都会显示相同的行号,因此更难发现。
如果由于某种原因经常发生这种情况,则表明foo_a()
应该在另一个可以模拟的源文件中。
【讨论】:
以上是关于如何在 C 中模拟同一 UUT 中的函数的主要内容,如果未能解决你的问题,请参考以下文章