[英]How to mock functions in headerfiles?
我在做什么:
我正在使用cmocka为大型嵌入式项目运行单元测试。 嵌入式项目使用arm-gcc-compiler
。 使用嵌入代码的片段和cmocka库,使用普通gcc
编译单元测试。
通常cmocka建议使用-Wl -Wl,--wrap=functionName
标志来模拟(替换)一些不需要的子函数。 这非常好用。
问题:
好吧,在我的嵌入式代码中有一个头文件( foo.h
),它包含一些函数(声明为内联)。 其中一个函数包含arm-gcc-compiler
一些汇编代码,当然,它不能由gcc
。
愚蠢的是, wrap
-flag似乎不适用于放在头文件中的函数。
题:
如何在头文件中模拟这个函数?
我是如何尝试解决问题的:
我想插入一些#idef
宏来排除提到的汇编程序部分。 但是这不可能,因为该文件属于许可库,我不允许更改其内容。
我可以将我的测试功能提取到另外的文件中,这样就不再需要包含foo.h
了。 但这会混淆嵌入式源代码结构。
确切的问题
确切的代码放在第233行的freeRtos的portmacro.h中:
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
__asm volatile
(
" mov %0, %1 \n" \
" msr basepri, %0 \n" \
" isb \n" \
" dsb \n" \
:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
其中portFORCE_INLINE
定义为:
#define portFORCE_INLINE inline __attribute__(( always_inline))
愚蠢的是,wrap-flag似乎不适用于放在头文件中的函数。
这不是wrap
的错,函数已被编译器内联,因此链接器无法做到。
如何在头文件中模拟这个函数?
一种选择是使用sed
在将其传递给gcc之前自动修补有问题的代码。 例如改变
portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;
...
}
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void )
{
uint32_t ulNewBASEPRI;
...
}
从你的例子到
portFORCE_INLINE static void vPortRaiseBASEPRI( void );
portFORCE_INLINE static void vPortRaiseBASEPRI_2( void );
做
cat tmp.c | sed '/inline\|INLINE/,/^}$/{ s/^\(.*\(inline\|INLINE\).*\)/\1;/; /inline\|INLINE/!d }'
正则表达式非常草率,它依赖于标题中的所有定义都将具有INLINE
标记但在您的情况下应该足够的事实。
您可以将上面的命令嵌入到Makefile中,以在temp文件夹中生成自定义标头,然后使用-Ipath/to/temp/folder
标志覆盖默认标头。
我没有使用cmocka所以我不确定是否有一种方法可以在框架内管理它。
但是, cmock使用一种方法,将标头复制到测试版本的包含层次结构中较高位置的位置(并且只有测试版本,即使发布版本也隐式包含该位置)。
然后可以编辑此标头的副本,使得函数声明只是变为port void vPortRaiseBASEPRI( void );
。 然后,当生成模拟时,会为此生成模拟(以及同一标头内的其他函数声明),就像在任何其他情况下一样。 因为正在生成hte模拟,所以函数没有匹配的源代码定义(即.c
文件)并不重要。
请参阅https://dmitryfrank.com/articles/unit_testing_embedded_c_applications上的“处理特定于编译器的内容”部分
我的类似问题以及我如何解决它: 使用编译器特定关键字对单元测试C进行单元测试
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.