问题描述
我开始进行单元测试,但在理解某些内容时遇到了麻烦.我的奋斗归结为如何测试仅在.c源代码中而不在.h头文件中声明的函数.有些功能不需要在实现之外调用,因为它们仅与该特定文件有关.由于它们对程序的其他部分不可见,这意味着我的单元测试用例文件看不到那些内部功能,因此使我无法对其进行测试.我已经通过在测试用例文件中使用前向声明解决了这个问题,但是这似乎有点混乱,并且如果我修改函数参数,改变它会很痛苦.
I'm starting to get into unit testing and I'm having trouble understanding something. My struggle boils down to how I would go about testing functions that are only in the .c source, and not declared in the .h header. There's certain functions that shouldn't need to be called outside of the implementation because they're only relevant to that specific file. Since they're not visible to other parts of the program, that means my unit testing cases file can't see those inner functions, therefore making me unable to test them. I've gone around the issue by using forward declarations in the test cases file, but that seems kinda messy and would get to be a pain to go and change if I modify the function parameters.
这些功能难道不是单元测试所涵盖的吗?我已经读过OOP,您不应该测试私有功能,因为它们是通过公共功能隐式测试的,但是不覆盖这些功能(某些功能可能会变得很复杂)感到不舒服.
Are these functions just not meant to be covered by unit testing? I've read that with OOP, you shouldn't be testing private functions because they're tested implicitly through the public functions, but it feels uncomfortable to not have these functions covered (some of which can get quite complex).
推荐答案
黑盒测试是关于测试您公开可见的界面与用户之间的软件合同.为了测试这一点,通常使用工具或单独的测试程序创建一组测试用例,该测试用例是#include
的头文件.h,它定义了外部接口.听起来您已经有了这个.太好了!
Blackbox testing is about testing the software contract between your publicly visible interface and the users. To test this, one typically creates a set of test cases using a tool or a separate test program, that #include
's your header file .h which defines your external interfaces. Sounds like you already have this. Great!
缺少的是白盒测试的概念.对于许多行业,例如电信,铁路,航空航天或任何其他需要高度确保高可用性和高质量的行业,这与黑匣子测试一样重要.
What is missing is the concept of White Box testing. This is every bit as important as black box testing for many industries such as telecom, railways, aerospace, or any other industry where high availability and quality need to be assured to a high degree.
对于白盒测试,请创建一个单独的专用"界面,该界面仅由您的白盒测试程序使用.注意,在C
中,您可以为给定的C实现文件创建多个头文件.从编译器的角度来看,并没有真正强制执行标头或其名称的数量.最好遵守项目或团队所规定的约定.
For White Box testing, create a separate "private" interface that is used only by your White Box test program. Notice, that in C
you can create multiple header files for a given C implementation file. From the compiler's perspective, there is no real enforcement of the number of headers or their names. It is best to stick to a convention as dictated by your project or team.
对于我们的项目,我们为外部接口创建一个公共头(带有简单的.h后缀),为我们的私有接口创建一个私有头(_pi.h),供需要访问私有接口(例如,白盒测试,审核数据结构,内部配置和诊断以及调试工具.当然,_pi.h后缀只是一个约定,但是在实践中效果很好.
For our projects, we create a public header (with a simple .h suffix) for our external interfaces, and private header (_pi.h) for our private interfaces intended for a select few who need to access private interfaces such as white box testing, auditing data structures, internal provisioning and diagnostics, and debug tools. Of course, the _pi.h suffix is just a convention, but it works well in practice.
白盒测试对于测试内部功能和数据结构非常有用,并且可以远远超出黑盒测试的范围.例如,我们使用White Box测试用例测试内部接口,并查看数据结构损坏时会发生什么情况,以及诸如在内部传递意外参数值时测试代码的工作等极端情况.
White Box testing is very useful to test your internal functions and data structures, and can go well beyond the limits of Black Box testing. For example, we use White Box test cases to test internal interfaces, and to see what happens when our data structures get corrupted, as well as corner cases such as testing what our code does when passed an unexpected parameter value internally.
例如,假设我们有一个名为foo.c的文件,我们希望对其进行白盒测试.然后,我们将创建两个标头:foo.h和foo_pi.h分别用于外部和内部用户.
For example, let's say we have a file called foo.c that we wanted to perform white box testing on. Then we would create two headers: foo.h and foo_pi.h for external and internal users respectively.
文件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
If you are confused what all those #ifndef
/#define
/#endif
things are, these are CPP
macros, and this use is not enforced in C but it is a widely used convention. For more details, see https://stackoverflow.com/a/42744341/6693299
虽然我在上面的示例中没有显示它,但是Foobar_test()例程(以及任何其他内部测试方法)通常会放置在为内部测试功能保留的单独模块中,然后可以将它们打包到最终版本之外.除了一些我这里将不介绍的精美的CPP预处理之外,您还可以有条件地编译出专用头文件和测试函数,并使接口对生产负载安全(在完成白盒测试之后).可能太多了!
While I did not show it in the example above, the Foobar_test() routine (and any other internal test methods, would typically be placed in a separate module reserved for internal test functions. Then they can be packaged out of the final product. Along with some fancy CPP preprocessing that I won't describe here, you can conditionally-compile out the private headers and the test functions, and make the interface secure for the production load (after White Box testing is done). But that is probably too much detail!
这篇关于功能未包含在标题中的单元测试C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!