函数不在标头中的单元测试C

vhipe2zx  于 2023-01-04  发布在  其他
关注(0)|答案(2)|浏览(139)

我开始进入单元测试,但我在理解一些东西时遇到了困难。我的困难归结为如何测试那些只在.c源代码中,而不在.h头文件中声明的函数。有些函数不应该在实现之外调用,因为它们只与特定的文件相关。因为它们对程序的其他部分不可见,这意味着我的单元测试用例文件不能看到那些内部函数,因此使我无法测试它们。我已经通过在测试用例文件中使用前向声明来绕过这个问题,但这看起来有点混乱,如果我修改函数参数,那么改变它会很痛苦。
这些函数是不是不应该被单元测试覆盖?我读到过,使用OOP时,你不应该测试私有函数,因为它们是通过公共函数隐式测试的,但是没有覆盖这些函数会让人感觉不舒服(其中一些函数可能会变得相当复杂)。

63lcw9qa

63lcw9qa1#

黑盒测试是关于测试你的公开可见界面和用户之间的软件契约。为了测试这个,人们通常使用一个工具或一个单独的测试程序创建一组测试用例,#include是你的头文件.h,它定义了你的外部接口。听起来你已经有了这个。太棒了!
缺少的是白色盒测试的概念。对于许多行业,如电信、铁路、航空航天或任何其他需要高度保证高可用性和质量的行业,白盒测试与黑盒测试一样重要。
对于白色盒测试,创建一个单独的“私有”接口,仅由白盒测试程序使用。请注意,在C中,您可以为给定的C实现文件创建多个头文件。从编译器的Angular 来看,没有真实的强制头文件的数量或名称。最好遵守项目或团队规定的约定。
在我们的项目中,我们为外部接口创建了一个公共头(带有一个简单的.h后缀),为私有接口创建了私有头(_pi. h),这些私有接口是为少数需要访问私有接口的人设计的,比如白色盒测试、审计数据结构、内部供应和诊断以及调试工具。当然,_pi. h后缀只是一个约定,但在实践中效果很好。
白色盒测试对于测试内部函数和数据结构非常有用,并且可以远远超出黑盒测试的限制。例如,我们使用白盒测试用例来测试内部接口,并查看当我们的数据结构损坏时会发生什么,以及测试代码在内部传递意外参数值时会发生什么等极端情况。
例如,假设我们有一个名为foo.c的文件,我们想对它执行白色盒测试,那么我们将创建两个头文件:foo. h和foo_pi. h分别用于外部和内部用户。

文件名h

#ifndef FOO_H
#define FOO_H

typedef int FooType;

// Public header for Foo
void Foo(FooType fooVal);
void Bar(void);

#endif

文件foo_pi.h

#ifndef FOO_PI_H
#define FOO_PI_H

// PI should also include the public interface
#include "foo.h"

// Private header for Foo
// Called by White Box test tool 
void FooBar_Test1(FooType fooVal);
void Foo_Internal(void);
void Bar_Internal(void);

#endif

文件foo.c

#include "foo.h"
#include "foo_pi.h"
// Notice you need to include both headers

// Define internal helpers here
static FooType myFooVal = 0; 
void FooBar_Test1(FooType fooVal) {myFooVal = fooVal;}

void Foo_Internal() {Bar_Internal();}
void Bar_Internal(void) {myFooVal++;}      

// Define external interfaces after the helpers
void Foo(FooType fooVal) {myFooVal = fooVal; Foo_Internal();}
void Bar(void)           {Bar_Internal();}

// Main() not typically included 
// if this is just one module of a bigger project!
int main(int argc, char** argv)
{
 Foo(argc);
}

如果你搞不清那些#ifndef/#define/#endif是什么,那么这些就是CPP宏,这种用法在C语言中没有强制执行,但它是一种广泛使用的约定。
虽然我没有在上面的示例中显示它,但是Foobar_test()例行程序(以及任何其他内部测试方法,通常会被放置在一个为内部测试函数保留的单独模块中。然后,可以将它们打包到最终产品之外。除了一些我在这里不会描述的花哨的CPP预处理之外,您还可以条件编译出私有标头和测试函数,并使接口对于生产负载是安全的(在白色盒测试完成之后)。但这可能是太多的细节!
@doug-currie的帖子提供了一个关于如何使用CPP宏通过条件编译排除测试代码的有用描述。

js4nwp54

js4nwp542#

@ScottK对黑盒与白盒测试的描述很有用,我对白盒测试的方法是不同的。
根据项目结构,我可以

  • 将单元测试放在与被测单元相同的文件中,通常放在文件末尾,所有测试都放在#if UNIT_TEST... #endif
  • #include单元测试代码中被测C文件;这提供了对所有内部函数的访问,而无需对原始源代码进行任何更改

相关问题