单元测试存根 C 辅助方法
我正在寻找一种方法来删除位于同一 C 文件中的辅助方法。有没有什么方法可以在不修改源文件的情况下做到这一点?我正在考虑使用 #define
将方法 b
替换为 b_stub
方法,但我认为这最终会重命名方法 b
下面是一个示例用例:
#include "file.h"
a(){
b();
}
b(){
}
我正在尝试创建一个测试框架,但我希望用户只需包含一个包含框架和存根定义的文件。
谢谢。
I am looking for a way to stub out a helper method located within the same C file. Is there any way of doing this without modifying the source file? I was thinking something along the lines of using a #define
to replace method b
with a b_stub
method, but I think this will end up renaming the method b
Here's a sample use case:
#include "file.h"
a(){
b();
}
b(){
}
I am attempting to create a testing framework, but I want the user to only have to include a single file containing the framework and stub definitions.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不确定我完全理解你的问题。
如果您想调用与
b
不同的例程,那么您可以在编译时执行以下操作:或者如果您总是想调用
b
但想要b 要表现不同,您可以在编译时执行以下操作:
或者您可以在运行时执行类似的操作(为简单起见,使用全局变量在此处显示):
或
使用编译时示例,您可以通过更改来来回切换头文件或 Makefile 定义。通过运行时示例,您可以使用命令行选项、环境变量、用户首选项窗格或其他任何内容来回切换。
I am not sure I completely understand your question.
If you want to call a different routine than
b
then you can do it at compile time as:Or if you always want to call
b
but wantb
to behave differently, you can do it at compile time as:Or you can do similar things at runtime with (shown here with a global variable for simplicity):
or
With the compile-time examples you can switch back and forth by changing a header file or a Makefile definition. With the runtime examples you can switch back and forth with a command line option, environment variable, user preference pane, or anything else.
我找到了一个适合我的解决方案,也许它也会对您有所帮助。
单独使用 MACROS 只能让您到目前为止。如果您想对某个函数执行测试,然后使用 MACROS 以各种不同的方式将其存根,则需要您多次重建代码并单独运行每个条件。这很难自动化 - 现在您必须有一个批处理脚本来定义不同的符号并重建代码并聚合结果。
但是,如果您使用 MACROS 为要删除的每个函数定义一个函数指针,假设您可以对要测试的目标代码进行一些小的修改,那么您就有了一个可行的解决方案。
以下示例深受以下影响:
MUT 在此示例中代表被测模块。
假设您有四个文件:mut.h、mut.c、test_mut.h、test_mut.c。我们还假设您可以在构建时定义一个符号 UNIT_TEST 。
mut.h 将包含任何可公开访问的函数。对于这个例子来说,没有任何东西,所以让我们忘记它。
因此,让我们从 mut.c 的一个版本开始,
假设我们已经对 bar 进行了单元测试。效果很好。现在我们想要测试 foo,但我们不想设置我们需要的所有内容以使 bar 正确执行。所以我们需要将 bar 剔除。
因此,让我们包含一个新标头 test_mut.h。除此之外,您还会在 test_mut.h 中包含以下内容。
因此,正如您所看到的,我们定义了一个新的函数指针,它现在可以指向我们的存根/模拟或我们真正的 bar 函数。该标头也将包含在 test_mut.c 中,因此存根函数现在可以在 test_mut.c 内部定义 - 它们不需要在 mut.c 中使其混乱。
现在让这个变得有用,我们需要稍微修改 mut.c
mut.c 现在需要包含“test_mut.h”,在单元测试期间需要禁用 bar() 的标准声明,并且我们需要更改定义将函数添加到 bar_real()
您需要存根的每个函数都需要类似的 #ifdef 并围绕声明和定义进行重命名。因此,不幸的是,您的测试代码需要变得有点混乱。
现在 test_mut.c 现在可以按如下方式运行您的代码:
以下是我的源文件的一些完整列表。我在这里构建了一个轻量级测试工具,它在 IAR 嵌入式工作台编译器上编译和运行(我没有在其他任何东西上尝试过)并生成以下输出
mut.c
test_mut.h
test_mut.c
I found a solution to this that works for me, maybe it will help you too.
Using MACROS by themselves can only get you so far. If you want to perform a test on a function but then stub it out in various different ways using MACROS will require you to rebuild your code several times and run each condition individually. This is tricky to automate - now you have to have a batch script that will define different symbols and rebuild the code and aggregate the results.
However, if you use MACROS to define a function pointer for each function you which to stub out you have a workable solution assuming you can make some minor modifications to the target code you wish to test.
The following example was heavily influenced by the following:
MUT stands for module under test in this example.
Lets assume you have four files: mut.h, mut.c, test_mut.h ,test_mut.c. Lets also assume you can define a symbol UNIT_TEST when you build this.
mut.h would include any functions that are publicly accessible. For this example there aren't any, so lets forget it.
So lets start off with a version of mut.c
Let's assume we've already unit tested bar. It works fine. Now we want to test foo but we don't feel like setting everything up that we need to in order to make bar execute properly. So we need to stub bar out.
So lets include a new header, test_mut.h. Among other things you would have the following in test_mut.h
So, as you can see we've define a new function pointer that can now point to our stubs/mocks or to our real bar function. This header will also be included in test_mut.c so the stubbed functions can now be defined inside of test_mut.c - they don't need to be in mut.c cluttering it up.
Now lets make this useful, we need to modify mut.c slightly
mut.c will now need to include "test_mut.h", the standard declaration of bar() needs to be disabled during unit testing, and we need to change the definition of the function to bar_real()
Every function you need to stub out will need similar #ifdefs and renaming around the declaration and definition. So your code under test will need to get a little bit cluttered unfortunately.
Now test_mut.c can now exercise your code as follows:
Here are some full listings of my source files. I've built a lightweight test harness here and it compiles and runs on the IAR embedded workbench compiler (I haven't tried it on anything else) and produces the following output
mut.c
test_mut.h
test_mut.c
如果这是在框架代码中而不是最终用户代码中,那么您可以执行类似的操作
,现在当您想在 B 上运行单元测试时,您可以定义 UNIT_TEST_FUNC_B 并将存根代码包含在单独的模块中
,或者如果您想保留在同一模块中测试代码,您可以执行此操作,
我为定义使用了唯一的名称,以便您可以为不同的测试存根不同的函数。
If this is in the framework code and not end user code then you can do something like this
and now when you want to run the unit test on B you define UNIT_TEST_FUNC_B and include the stub code in a separate module
or if you want to keep the test code in the same module, you do this
I used a unique name for the define so you can stub out different functions for different tests.
您必须修改源代码,但不要修改太多。
现在尝试一下
,对方法 b() 的调用将被 Stub_b() 替换,并且 b() 定义将保持不变。 :)
You have to modify the source but not much.
Try this
now calls to method b() will be replaced by stub_b() and b() defination will remain unchanged. :)