gpt4 book ai didi

c - 函数不在头文件中的单元测试 C

转载 作者:太空狗 更新时间:2023-10-29 14:55:49 25 4
gpt4 key购买 nike

我开始进行单元测试,但我无法理解某些内容。我的挣扎归结为我将如何测试仅在 .c 源中而不在 .h header 中声明的函数。有些函数不需要在实现之外调用,因为它们只与特定文件相关。由于它们对程序的其他部分不可见,这意味着我的单元测试用例文件看不到这些内部函数,因此我无法测试它们。我已经通过在测试用例文件中使用前向声明解决了这个问题,但这看起来有点困惑,如果我修改函数参数,改变起来会很痛苦。

难道这些功能不应该包含在单元测试中吗?我读过关于 OOP 的内容,你不应该测试私有(private)函数,因为它们是通过公共(public)函数隐式测试的,但不覆盖这些函数会让人感觉不舒服(其中一些函数可能会变得非常复杂)。

最佳答案

黑盒测试是关于测试公开可见的界面和用户之间的软件契约。为了对此进行测试,人们通常使用工具或单独的测试程序创建一组测试用例,#include 是您的头文件 .h,它定义了您的外部接口(interface)。听起来你已经有了这个。太棒了!

缺少的是白盒测试的概念。对于电信、铁路、航空航天或任何其他需要高度保证高可用性和质量的行业,这与黑盒测试一样重要。

对于白盒测试,创建一个单独的“私有(private)”接口(interface),仅供您的白盒测试程序使用。请注意,在 C 中,您可以为给定的 C 实现文件创建多个头文件。从编译器的角度来看,并没有真正强制执行 header 的数量或其名称。最好遵守您的项目或团队规定的惯例。

对于我们的项目,我们为我们的外部接口(interface)创建了一个公共(public) header (带有一个简单的 .h 后缀),并为我们的私有(private)接口(interface)创建了一个私有(private) header (_pi.h),供少数需要访问私有(private)接口(interface)的人使用,例如白盒测试、审计数据结构、内部配置和诊断以及调试工具。当然,_pi.h 后缀只是一种约定,但在实践中效果很好。

白盒测试对于测试您的内部功能和数据结构非常有用,并且可以远远超出黑盒测试的限制。例如,我们使用白盒测试用例来测试内部接口(interface),看看当我们的数据结构被破坏时会发生什么,以及测试当内部传递一个意外的参数值时我们的代码做了什么的极端情况。

例如,假设我们有一个名为 foo.c 的文件,我们想对其执行白盒测试。然后我们将创建两个 header :分别用于外部和内部用户的 foo.h 和 foo_pi.h。

文件 foo.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 中并未强制执行,但它是一种广泛使用的约定。有关详细信息,请参阅 https://stackoverflow.com/a/42744341/6693299

虽然我没有在上面的例子中展示它,但 Foobar_test() 例程(以及任何其他内部测试方法,通常会被放置在一个单独的模块中,为内部测试函数保留。然后它们可以从最终的模块中打包出来产品。连同我不会在这里描述的一些花哨的 CPP 预处理,您可以有条件地编译出私有(private) header 和测试函数,并使接口(interface)对于生产负载是安全的(在完成白盒测试之后)。但是可能是太详细了!

@doug-currie 的帖子提供了有关如何使用 CPP 宏通过条件编译排除测试代码的有用描述。

关于c - 函数不在头文件中的单元测试 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46531419/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com