当前位置: 首页 > news >正文

C之(10)CMocka-单元测试框架使用

CMocka基础使用

Author:Once Day Date:2023年6月15日

参考文档:

  • GoogleTest User’s Guide | GoogleTest
  • 嵌入式自动化单元测试(2)-Cmocka - 知乎 (zhihu.com)
  • 使用 cmocka 进行单元测试 | 前尘逐梦 (qianchenzhumeng.github.io)
  • cmocka - unit testing framework for C

文章目录

      • CMocka基础使用
        • 1. 概述
          • 1.1 介绍
          • 1.2 特性
          • 1.3 注意事项
        • 2. 基本用法
          • 2.1 MOCK对象使用
          • 2.2 检查MOCK函数输入参数
          • 2.3 断言宏
          • 2.4 函数调用顺序
          • 2.5 运行测试
          • 2.6 内存检查
          • 2.7 标准断言

1. 概述
1.1 介绍

CMocka 是一个用于 C 语言的单元测试框架,它是 Check 单元测试框架的一个分支。CMocka 的设计哲学是“只做一件事,但做得好”,这使得它成为一个轻量级、易于使用的工具。它为测试 C 代码提供了一种简单、稳定的方法。

以下是使用 CMocka 的一些主要特性:

  1. 轻量级和模块化:CMocka 不需要复杂的设置,不依赖于其他库,且不会大幅度地增加你的项目大小。你可以简单地将其添加到你的 C 项目中,然后开始编写测试。

  2. 模拟函数:在进行单元测试时,我们通常需要模拟一些函数以便在特定条件下测试我们的代码。CMocka 提供了一个功能强大的模拟函数系统,你可以方便地使用它来模拟你的函数。

  3. 断言:CMocka 提供了一组断言宏,你可以使用这些断言来验证你的代码的行为。这些断言会在测试失败时提供有用的错误信息。

  4. 组织测试:CMocka 提供了一种简单的方式来组织你的测试。你可以将测试分组,然后一次运行一个组,或者运行所有组的测试。

  5. 端到端的测试:与只关注单元测试的一些其他框架不同,CMocka 也支持端到端的测试。这使得你可以在一个统一的环境中进行所有的测试。

以下是一个简单的 CMocka 测试用例示例:

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>// The function to test
int add(int a, int b) {return a + b;
}// The test case function
void test_add(void **state) {assert_int_equal(add(2, 2), 4);
}int main(void) {const struct CMUnitTest tests[] = {cmocka_unit_test(test_add),};return cmocka_run_group_tests(tests, NULL, NULL);
}

在这个例子中,我们首先定义了一个名为 add 的函数,然后定义了一个测试用例 test_add,这个测试用例使用 assert_int_equal 断言来检查 add 函数的结果是否正确。最后,我们在 main 函数中运行这个测试用例。

更多关于 CMocka 的信息,你可以参考其官方文档。

1.2 特性

这个项目的目标是在不同的平台和操作系统上为C提供一个强大的测试框架,它只需要标准的C库。

  • 支持模拟对象,Mock对象是模拟对象,用于模拟实际对象的实际实现。可用于模拟接口的依赖项,以帮助单独测试接口。一些项目使用mock功能来模拟通过网络通信的组件。
  • 只需要一个C库,这使得cmocka可以在许多嵌入式平台上工作。
  • 几种支持的输出格式,cmocka支持几种不同的消息输出格式,如Test Anything Protocol、Subunit、xUnit XML或原始cmock输出格式。
  • 完全文档化的API,该API有很好的文档记录,cmoka为它提供的不同特性提供了几个示例。
  • 测试fixture,测试fixture是可以在多个测试用例之间共享的设置和拆除功能,以提供准备测试环境并在之后销毁测试环境的公共功能。
  • 信号(SIGSEGV, SIGILL,…)的异常处理,如果出现异常,如段故障,cmoka能够恢复测试状态。
  • 没有fork() ,Cmocka在测试用例中不使用fork()进行异常处理。
  • 经过了很好的测试,Cmocka有每晚夜间构建,可以在多个平台和不同的编译器上进行测试,以确保它能正常工作。如果你想让它在你的平台上工作,你可以添加一个每晚夜间夜间构建,我们将确保不会破坏你的平台或编译器。
  • 测试内存泄漏,缓冲区溢出和下溢。我们在测试过程中提供了一些功能,这些功能可以在不运行valgrind等工具的情况下检测到某些类型的内存分配问题。
  • cmockery兼容支持,Cmocka是cmock的派生和继承者。我们提供了cmock头文件的安装,以便您为cmock编写的测试在迁移到cmock之前仍然可以工作。
  • 平台和编译器,cmocka在Linux、BSD、Solaris、Windows和嵌入式平台上运行良好。众所周知,它可以与GCC、LLVM、MSVC、MinGW等一起工作。

CMocka 使用 Apache License 2.0 进行许可。这是一个宽松的开源许可证,允许你自由地使用、复制和分发软件,无论是在开源还是闭源的项目中。

Apache License 2.0 的主要特点包括:

  1. 商业友好:你可以在你的商业产品中使用和分发使用 Apache License 2.0 许可的软件,而无需支付费用。

  2. 版权声明:你必须在你分发的所有副本和重要部分的版权声明中,保留使用 Apache License 2.0 许可的软件的版权声明。

  3. 状态变更:如果你修改了使用 Apache License 2.0 许可的软件,你必须在修改的文件中添加一个明显的标记,表示你做了修改。

  4. 免责声明:Apache License 2.0 包含一个免责声明,声明软件是“按原样”提供,不提供任何明示或暗示的保证。

请注意,这只是 Apache License 2.0 的一个简单概述,对于具体的法律条款和细节,应该参考完整的 Apache License 2.0 文本。

1.3 注意事项

嵌入式平台,有些嵌入式平台可能不提供所需类型的定义,或者保护它们的防护措施没有定义。为了解决这个问题,你可以创建一个名为 ‘cmocka_platform.h’ 的头文件,其中包含所需的类型和定义。然后,使用以下命令将 cmake 指向包含目录:

cmake -DCMOCKA_PLATFORM_INCLUDE=/home/compiler/my/include_directory ..

线程,CMocka 并不完全线程安全,它的目标也不是要实现线程安全。我们有几个全局变量来跟踪测试状态。它们被标记为线程本地的,但你可能会遇到问题。然而,如果你在使用线程的应用程序中编写测试,你可以设置以下环境变量:

CMOCKA_TEST_ABORT='1' ./my_threading_test

将此环境变量设置为 ‘1’,如果测试失败,CMocka 将调用 abort() 函数。

CMocka 提供了多种测试结果的输出格式。特定的格式可以通过使用 CMOCKA_MESSAGE_OUTPUT 环境变量来配置。此变量接受几个值,每个值对应一个不同的输出格式

  • STDOUT:这是默认的输出格式。它将人类可读的测试输出打印到标准输出。
  • SUBUNIT:该选项将以 Subunit 格式生成输出,这是一种允许测试工具以机器可读的格式交流测试结果的协议。
  • TAP:此选项将以 Test Anything Protocol (TAP) 格式生成输出。TAP 是一种文本基础的协议,用于以标准化的方式报告测试结果,从而允许其他工具进行简单的解析。
  • XML:此选项将以 JUnit XML 格式生成输出。这是一种报告测试结果的标准 XML 格式,广泛用于持续集成服务器。

所有这些选项都不区分大小写。默认情况下,XML 输出会发送到标准错误(stderr)。但是,如果设置了 CMOCKA_XML_FILE 环境变量并指向一个不存在的文件,CMocka 将把 XML 输出写入该文件。

如果你在多个组中运行测试并希望为每个组生成一个单独的 XML 文件,可以将 CMOCKA_XML_FILE 设置为 CMOCKA_XML_FILE=cm_%g.xml。这里的 %g 占位符将被每个测试的组名替换,为每个组创建一个唯一的文件。如果你不这样设置,所有组的结果将被打印到同一个文件中。

2. 基本用法
2.1 MOCK对象使用

模拟对象(Mock objects)是模拟真实对象行为的仿真对象。在测试中,被测试对象不会调用真实对象,而是调用一个模拟对象,该模拟对象仅仅断言是否以正确的顺序、以预期的参数调用了正确的方法。

will_return(function, value) - will_return() 宏将一个值压入模拟值堆栈中。这个宏主要由单元测试本身使用,以编程模拟对象的行为。

mock() - mock 宏从测试值堆栈中弹出一个值。mock() 宏的用户是模拟对象,使用它来了解自己应该如何行为。
由于 will_return()mock() 预期要成对使用,如果使用 will_return() 将更多的值压入堆栈而未通过 mock() 消耗,或者反之,则 cmocka 库会使测试失败。

以下的单元测试示例说明了如何指示模拟对象返回特定的值:

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>/* 假设这是我们要模拟的函数 */
int function_to_mock(int arg) {return (int)mock();
}/* 我们的单元测试 */
void test_function(void **state) {/* 指示模拟函数返回42 */will_return(function_to_mock, 42);/* 在这里,我们调用了函数,它会调用我们的模拟函数 */int result = some_function_that_calls_function_to_mock();/* 验证结果 */assert_int_equal(result, 42);
}int main(void) {const struct CMUnitTest tests[] = {cmocka_unit_test(test_function),};return cmocka_run_group_tests(tests, NULL, NULL);
}

在这个例子中,some_function_that_calls_function_to_mock() 是调用我们模拟的函数的函数。我们通过 will_return 告诉模拟函数返回42,然后验证返回的结果是否正确。

目前有以下函数可以使用:

LargestIntegralType mock (void)Retrieve a return value of the current function. 
type mock_ptr_type (#type)Retrieve a typed return value of the current function. 
void will_return (#function, LargestIntegralType value)Store a value to be returned by mock() later. 
void will_return_count (#function, LargestIntegralType value, int count)Store a value to be returned by mock() later. 
void will_return_always (#function, LargestIntegralType value)Store a value that will be always returned by mock().
void will_return_maybe (#function, LargestIntegralType value)Store a value that may be always returned by mock().
2.2 检查MOCK函数输入参数

当我们需要对传入模拟函数的参数进行检查时,可以使用 expect_*() 函数(如 expect_string(), expect_value() 等)来设定预期的参数值。然后,在模拟函数中,我们可以使用 check_expected() 宏来检查实际参数是否符合预期。

如果连续调用同一个参数的 expect_*() 宏,那么这些预期值将会被依次加入队列。check_expected() 会将函数参数与使用 expect_*() 队列中的下一个值进行比较。如果参数检查失败,测试将标记为失败。此外,如果调用 check_expected() 时,队列中已无参数值,测试也将标记为失败。

以下是如何使用这些功能的示例。首先,我们在测试驱动中调用一个函数:

static void test_driver(void **state)
{expect_string(chef_cook, order, "hotdog");
}

现在,chef_cook 函数可以检查传入的参数是否符合测试驱动的预期。这可以通过以下方式完成:

int chef_cook(const char *order, char **dish_out)
{check_expected(order);
}

在这个例子中,test_driver 函数预期 chef_cookorder 参数为 “hotdog”。然后,在 chef_cook 函数中,我们通过 check_expected(order) 来检查实际的 order 参数是否为 “hotdog”。

目前有以下函数可以使用:

void expect_check (#function, #parameter, #check_function, const void *check_data)Add a custom parameter checking function. 
void expect_in_set (#function, #parameter, LargestIntegralType value_array[])Add an event to check if the parameter value is part of the provided array. 
void expect_in_set_count (#function, #parameter, LargestIntegralType value_array[], size_t count)Add an event to check if the parameter value is part of the provided array.
void expect_not_in_set (#function, #parameter, LargestIntegralType value_array[])Add an event to check if the parameter value is not part of the provided array.
void expect_not_in_set_count (#function, #parameter, LargestIntegralType value_array[], size_t count)Add an event to check if the parameter value is not part of the provided array.
void expect_in_range (#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum)Add an event to check a parameter is inside a numerical range. The check would succeed if minimum <= value <= maximum.
void expect_in_range_count (#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum, size_t count)Add an event to repeatedly check a parameter is inside a numerical range. The check would succeed if minimum <= value <= maximum.
void expect_not_in_range (#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum)Add an event to check a parameter is outside a numerical range. The check would succeed if minimum > value > maximum.
void expect_not_in_range_count (#function, #parameter, LargestIntegralType minimum, LargestIntegralType maximum, size_t count)Add an event to repeatedly check a parameter is outside a numerical range. The check would succeed if minimum > value > maximum.
void expect_value (#function, #parameter, LargestIntegralType value)Add an event to check if a parameter is the given integer based value.
void expect_value_count (#function, #parameter, LargestIntegralType value, size_t count)Add an event to repeatedly check if a parameter is the given integer based value.
void expect_not_value (#function, #parameter, LargestIntegralType value)Add an event to check if a parameter isn't the given value.
void expect_not_value_count (#function, #parameter, LargestIntegralType value, size_t count)Add an event to repeatedly check if a parameter isn't the given value.
void expect_string (#function, #parameter, const char *string)Add an event to check if the parameter value is equal to the provided string.
void expect_string_count (#function, #parameter, const char *string, size_t count)Add an event to check if the parameter value is equal to the provided string.
void expect_not_string (#function, #parameter, const char *string)Add an event to check if the parameter value isn't equal to the provided string.
void expect_not_string_count (#function, #parameter, const char *string, size_t count)Add an event to check if the parameter value isn't equal to the provided string.
void expect_memory (#function, #parameter, void *memory, size_t size)Add an event to check if the parameter does match an area of memory.
void expect_memory_count (#function, #parameter, void *memory, size_t size, size_t count)Add an event to repeatedly check if the parameter does match an area of memory.
void expect_not_memory (#function, #parameter, void *memory, size_t size)Add an event to check if the parameter doesn't match an area of memory.
void expect_not_memory_count (#function, #parameter, void *memory, size_t size, size_t count)Add an event to repeatedly check if the parameter doesn't match an area of memory.
void expect_any (#function, #parameter)Add an event to check if a parameter (of any value) has been passed.
void expect_any_always (#function, #parameter)Add an event to always check if a parameter (of any value) has been passed.
void expect_any_count (#function, #parameter, size_t count)Add an event to repeatedly check if a parameter (of any value) has been passed.
void check_expected (#parameter)Determine whether a function parameter is correct.
void check_expected_ptr (#parameter)Determine whether a function parameter is correct.
2.3 断言宏

CMocka 提供的一系列有用的断言宏(assert macros),类似于标准 C 库的 assert(3) 宏。

在断言失败时,CMocka 的断言宏会将失败写入标准错误流,并标记测试失败。由于 C 语言的限制,通用的 C 标准库 assert() 以及 CMocka 的 assert_true()assert_false() 宏只能显示导致断言失败的表达式。而 CMocka 的类型特定断言宏,例如 assert_{type}_equal()assert_{type}_not_equal(),会显示导致断言失败的数据,这增加了数据可见性,有助于调试失败的测试用例。

以下是一些 CMocka 断言宏的例子:

  • assert_true(expression):断言表达式的结果为真(非零)。如果表达式结果为假(零),则测试失败。

  • assert_false(expression):断言表达式的结果为假(零)。如果表达式结果为真(非零),则测试失败。

  • assert_int_equal(a, b):断言两个整数相等。如果不相等,测试失败,并显示两个整数的值。

  • assert_string_equal(a, b):断言两个字符串相等。如果不相等,测试失败,并显示两个字符串的值。

这些断言宏极大地方便了单元测试的编写和结果的判断。

目前有以下函数可以使用:

void assert_true (scalar expression)Assert that the given expression is true.
void assert_false (scalar expression)Assert that the given expression is false.
void assert_return_code (int rc, int error)Assert that the return_code is greater than or equal to 0.
void assert_non_null (void *pointer)Assert that the given pointer is non-NULL.
void assert_null (void *pointer)Assert that the given pointer is NULL.
void assert_ptr_equal (void *a, void *b)Assert that the two given pointers are equal.
void assert_ptr_not_equal (void *a, void *b)Assert that the two given pointers are not equal.
void assert_int_equal (int a, int b)Assert that the two given integers are equal.
void assert_int_not_equal (int a, int b)Assert that the two given integers are not equal.
void assert_float_equal (float a, float b, float epsilon)Assert that the two given float are equal given an epsilon.
void assert_float_not_equal (float a, float b, float epsilon)Assert that the two given float are not equal given an epsilon.
void assert_double_equal (double a, double b, double epsilon)Assert that the two given double are equal given an epsilon.
void assert_double_not_equal (double a, double b, double epsilon)Assert that the two given double are not equal given an epsilon.
void assert_string_equal (const char *a, const char *b)Assert that the two given strings are equal.
void assert_string_not_equal (const char *a, const char *b)Assert that the two given strings are not equal.
void assert_memory_equal (const void *a, const void *b, size_t size)Assert that the two given areas of memory are equal, otherwise fail.
void assert_memory_not_equal (const void *a, const void *b, size_t size)Assert that the two given areas of memory are not equal.
void assert_in_range (LargestIntegralType value, LargestIntegralType minimum, LargestIntegralType maximum)Assert that the specified value is not smaller than the minimum and and not greater than the maximum.
void assert_not_in_range (LargestIntegralType value, LargestIntegralType minimum, LargestIntegralType maximum)Assert that the specified value is smaller than the minimum or greater than the maximum.
void assert_in_set (LargestIntegralType value, LargestIntegralType values[], size_t count)Assert that the specified value is within a set.
void assert_not_in_set (LargestIntegralType value, LargestIntegralType values[], size_t count)Assert that the specified value is not within a set.
2.4 函数调用顺序

这段文字说明了如何使用 CMocka 的 expect_function_call()function_called() 来验证函数调用的顺序。这与模拟返回值和参数检查是独立的,因为这两者并不检查它们从不同函数中被调用的顺序。

expect_function_call(function) - expect_function_call() 宏将预期调用推入预期调用堆栈。

function_called() - 从预期调用堆栈中弹出一个值。function_called() 在使用它的模拟对象中被调用。

expect_function_call()function_called() 预期成对使用。如果创建的预期调用(例如 expect_function_call())比通过 function_called() 消耗的预期调用多或少,CMocka 将使测试失败。在测试中,如果代码中的模拟调用并非测试的关注点,可以使用 ignore_function_calls() 等方法来绕过这个限制。function_called() 必须在与 expect_function_call() 相同的线程中调用,并且该线程必须已经被 CMocka 初始化(详见主文档页面的线程部分)。

以下的例子说明了如何在单元测试中指示 CMocka 预期从特定模拟 chef_sing() 中调用 function_called()

void chef_sing(void);void code_under_test()
{chef_sing();
}void some_test(void **state)
{expect_function_call(chef_sing);code_under_test();
}

然后,模拟的实现必须通过调用 function_called() 来检查是否应该被调用:

void chef_sing()
{function_called();
}

在这个例子中,some_test 函数预期 chef_sing() 会被调用。然后,在 chef_sing 函数中,我们通过 function_called() 来验证这个预期。

目前可用的函数如下:

void function_called (void)Check that current mocked function is being called in the expected order.
void expect_function_calls (#function, const int times)Store expected call(s) to a mock to be checked by function_called() later.
void expect_function_call (#function)Store expected single call to a mock to be checked by function_called() later.
void expect_function_call_any (#function)Expects function_called() from given mock at least once.
void ignore_function_calls (#function)Ignores function_called() invocations from given mock function
2.5 运行测试

下面的例子说明了如何使用 cmocka_unit_test 宏和 cmocka_run_group_tests 函数运行测试:

void Test0(void **state);
void Test1(void **state);int main(void)
{const struct CMUnitTest tests[] = {cmocka_unit_test(Test0),cmocka_unit_test(Test1),};return cmocka_run_group_tests(tests, NULL, NULL);
}

在这个例子中,我们有两个测试函数 Test0Test1。这些函数的参数是一个 void ** 指针,这是 CMocka 的标准测试函数签名。这个参数可以用于传递测试特定的状态或数据。

我们使用 cmocka_unit_test 宏将这些测试函数包装成 CMUnitTest 结构体,并放入一个数组中。

然后,我们使用 cmocka_run_group_tests 函数来运行这些测试。这个函数接受一个 CMUnitTest 结构体的数组,以及两个可选的回调函数,这些回调函数在测试组的开始和结束时被调用。在这个例子中,我们没有提供这些回调函数,所以传入 NULL

cmocka_run_group_tests 函数返回一个整数,表示测试的结果。如果所有测试都通过了,返回值为 0。如果有任何测试失败,返回值为非 0。这个返回值可以被用作程序的退出代码,以便于在脚本或连续集成系统中检查测试结果。

目前可用的宏定义:

#define 	unit_test(f)  { #f, f, UNIT_TEST_FUNCTION_TYPE_TEST }
#define 	_unit_test_setup(test, setup){ #test "_" #setup, setup, UNIT_TEST_FUNCTION_TYPE_SETUP }
#define 	unit_test_setup(test, setup)
#define 	_unit_test_teardown(test, teardown) { #test "_" #teardown, teardown, UNIT_TEST_FUNCTION_TYPE_TEARDOWN }
#define 	unit_test_teardown(test, teardown)
#define 	group_test_setup(setup)    { "group_" #setup, setup, UNIT_TEST_FUNCTION_TYPE_GROUP_SETUP }
#define 	group_test_teardown(teardown)    { "group_" #teardown, teardown, UNIT_TEST_FUNCTION_TYPE_GROUP_TEARDOWN }
#define 	unit_test_setup_teardown(test, setup, teardown)
#define 	cmocka_unit_test(f)   { #f, f, NULL, NULL, NULL }
#define 	cmocka_unit_test_setup(f, setup){ #f, f, setup, NULL, NULL }
#define 	cmocka_unit_test_teardown(f, teardown){ #f, f, NULL, teardown, NULL }
#define 	cmocka_unit_test_setup_teardown(f, setup, teardown){ #f, f, setup, teardown, NULL }
#define 	cmocka_unit_test_prestate(f, state){ #f, f, NULL, NULL, state }
#define 	cmocka_unit_test_prestate_setup_teardown(f, setup, teardown, state){ #f, f, setup, teardown, state }
#define 	run_tests(tests)_run_tests(tests, sizeof(tests) / sizeof((tests)[0]))
#define 	run_group_tests(tests)_run_group_tests(tests, sizeof(tests) / sizeof((tests)[0]))

目前可用的函数定义:

void 	fail (void)Forces the test to fail immediately and quit.
void 	skip (void)Forces the test to not be executed, but marked as skipped.
void 	fail_msg (const char *msg,...)Forces the test to fail immediately and quit, printing the reason.
int 	run_test (#function)Generic method to run a single test.
int 	cmocka_run_group_tests (const struct CMUnitTest group_tests[], CMFixtureFunction group_setup, CMFixtureFunction group_teardown)Run tests specified by an array of CMUnitTest structures.
int 	cmocka_run_group_tests_name (const char *group_name, const struct CMUnitTest group_tests[], CMFixtureFunction group_setup, CMFixtureFunction group_teardown)Run tests specified by an array of CMUnitTest structures and specify a name. More...
2.6 内存检查

如果要测试内存泄漏、缓冲区溢出和下溢,被 CMocka 测试的模块应将对 malloc(), calloc()free() 的调用替换为 test_malloc(), test_calloc()test_free()。每次使用 test_free() 释放一个块时,它都会被检查是否有损坏,如果找到损坏的块,则标记测试失败。CMocka 库跟踪所有使用 test_*() 分配函数分配的块。当测试完成时,如果有任何分配的块(内存泄漏)仍然存在,它们将被报告,并标记测试失败。

为了简单起见,CMocka 目前在一个进程中执行所有测试。因此,测试应用程序中的所有测试用例共享一个单一的地址空间,这意味着单个测试用例的内存损坏可能会导致测试应用程序提前退出。

下面是一些例子:

void some_function_under_test()
{char *data = test_malloc(100);// Do something with datatest_free(data);
}void some_test(void **state)
{some_function_under_test();// If some_function_under_test() didn't call test_free(), a memory leak would be reported
}

在这个例子中,我们在被测试的函数中使用 test_malloc() 分配了一些内存,然后在结束时使用 test_free() 释放了它。如果我们没有调用 test_free(),CMocka 就会报告一个内存泄漏。

目前可用的函数定义:

void * 	test_malloc (size_t size)Test function overriding malloc.
void * 	test_calloc (size_t nmemb, size_t size)Test function overriding calloc.
void * 	test_realloc (void *ptr, size_t size)Test function overriding realloc which detects buffer overruns and memoery leaks.
void 	test_free (void *ptr)Test function overriding free(3).
2.7 标准断言

像标准 C 库的 assert() 这样的运行时断言宏应该在被测试的模块中被重定义,以使用 CMocka 的 mock_assert() 函数。通常,mock_assert() 将标记一个测试失败。如果一个函数是用 expect_assert_failure() 宏调用的,那么函数内的任何 mock_assert() 调用都将导致测试的执行。如果在通过 expect_assert_failure() 调用的函数期间没有调用 mock_assert(),则会发出测试失败的信号。例如,你可以这样重定义 assert()

#undef assert
#define assert(value) mock_assert((int)(value), #value, __FILE__, __LINE__)

然后,你可以使用 expect_assert_failure() 来测试预期的断言失败:

void function_under_test()
{assert(0); // This will call mock_assert()
}void some_test(void **state)
{expect_assert_failure(function_under_test);// If function_under_test() didn't call mock_assert(), a test failure would be reported
}

在这个例子中,我们预期 function_under_test() 会调用 assert(0),这实际上会调用 mock_assert()。如果 function_under_test() 没有调用 mock_assert(),CMocka 就会报告测试失败。

目前可用的函数定义如下:

void 	mock_assert (const int result, const char *const expression, const char *const file, const int line)Function to replace assert(3) in tested code.
void 	expect_assert_failure (function fn_call)Ensure that mock_assert() is called.

相关文章:

C之(10)CMocka-单元测试框架使用

CMocka基础使用 Author&#xff1a;Once Day Date&#xff1a;2023年6月15日 参考文档&#xff1a; GoogleTest User’s Guide | GoogleTest嵌入式自动化单元测试(2)-Cmocka - 知乎 (zhihu.com)使用 cmocka 进行单元测试 | 前尘逐梦 (qianchenzhumeng.github.io)cmocka - un…...

如何在idea中使用maven搭建tomcat环境

目录 一、创建maven项目 二、完善代码结构 三、引入依赖和插件 四、启动tomcat&#xff0c;运行项目 &#xff08;1&#xff09;点击添加配置 &#xff08;2&#xff09;点击左上角的加号&#xff0c;选择maven &#xff08;3&#xff09;输入运行命令 五、验证 一、创建…...

单点登录

单点登录&#xff08;Single Sign-On&#xff0c;简称SSO&#xff09;是一种可以让用户在多个应用程序和网站中使用同一组登录凭证的技术&#xff0c;即用户只需通过一次身份验证&#xff0c;就可以访问多个应用和网站。以下是单点登录的相关知识点&#xff1a; 1. 身份验证机…...

大数据(十):数据可视化(二)

专栏介绍 结合自身经验和内部资料总结的Python教程&#xff0c;每天3-5章&#xff0c;最短1个月就能全方位的完成Python的学习并进行实战开发&#xff0c;学完了定能成为大佬&#xff01;加油吧&#xff01;卷起来&#xff01; 全部文章请访问专栏&#xff1a;《Python全栈教…...

pytorch+LSTM实现使用单参数预测,以及多参数预测(代码注释版)

开发前准备&#xff1a; 环境管理&#xff1a;Anaconda python: 3.8 显卡&#xff1a;NVIDIA3060 pytorch: 到官网选择conda版本&#xff0c;使用的是CUDA11.8 编译器&#xff1a; PyCharm 简述&#xff1a; 本次使用seaborn库中的flights数据集来做试验&#xff0c;我们通过…...

腾讯云3年/5年特惠云服务器购买入口及攻略

腾讯云是腾讯旗下云计算品牌&#xff0c;为了吸引用户经常推出各种优惠活动&#xff0c;最吸引用户的还是特惠云服务器&#xff0c;下面给大家分享腾讯云3年/5年时长特惠服务器购买入口及教程&#xff01; 购买入口&#xff1a;传送门>>> 购买攻略&#xff1a; 进入…...

【Linux】jdk Tomcat MySql的安装及Linux后端接口部署

一&#xff0c;jdk安装 1.1 上传安装包到服务器 打开MobaXterm通过Linux地址连接到Linux并登入Linux&#xff0c;再将主机中的配置文件复制到MobaXterm 使用命令查看&#xff1a;ll 1.2 解压对应的安装包 解压jdk 解压命令&#xff1a;tar -xvf jdk 加键盘中Tab键即可…...

天空卫士为集度智能汽车系上“安全带”

10月27日&#xff0c;集度汽车在北京正式发布了旗下首款量产车型——极越 01 SUV。极越 01 SUV 是一款集科技、智能、美学于一身的纯电动中大型SUV&#xff0c;号称全球首款“AI 汽车机器人”。作为集度的合作伙伴&#xff0c;天空卫士第一时间送上祝福&#xff0c;祝愿极越大卖…...

vue el-table-column 修改一整列的背景颜色

目录 修改表头以及一整列数据的背景颜色&#xff0c;效果如下&#xff1a; 总结 修改表头以及一整列数据的背景颜色&#xff0c;效果如下&#xff1a; 修改表头背景颜色&#xff1a;在el-table绑定header-cell-style 修改一整列的数据背景颜色&#xff1a;在el-table绑定:cel…...

docker 安装 minio (单体架构)

文字归档&#xff1a;https://www.yuque.com/u27599042/coding_star/qcsmgom7basm6y64 查询 minio 镜像 docker search minio拉取镜像 docker pull minio/minio创建启动 minio 容器 用户名长度至少为 3&#xff0c;密码长度至少为 8 docker run \ -p 9000:9000 \ -p 9090:909…...

docker搭建kafka

1.拉取zookeeper镜像 注意&#xff1a;云服务器需要设置安全策略放行2181与9092端口&#xff0c;否则访问失败 #默认拉取最新版本镜像 docker pull wurstmeister/zookeeper#检查镜像是否拉取成功 docker images | grep zookeeper2.通过docker运行zookeeper #docker容器单机启…...

给Nginx配置环境变量

给Nginx配置环境变量 Nginx安装目录下的二进制可执行文件nginx的很多命令&#xff0c;要想使用这些命令前提是需要进入sbin目录下才能使用&#xff0c;很不方便&#xff0c;如何去优化&#xff0c;我们可以将该二进制可执行文件加入到系统的环境变量&#xff0c;这样的话在任何…...

CHS零壹视频恢复程序高级版视频修复OCR使用方法

目前CHS零壹视频恢复程序监控版、专业版、高级版已经支持了OCR&#xff0c;OCR是一种光学识别系统&#xff0c;高级版最新版本中不仅仅是在视频恢复中支持OCR&#xff0c;同时视频修复模块也增加了OCR功能&#xff0c;此功能可以针对一些批量修复的视频文件&#xff08;如执法仪…...

android display 杂谈(三)WMS

用来记录学习wms&#xff0c;后续会一点一点更新。。。。。。 代码&#xff1a;android14 WMS是在SystemServer进程中启动的 在SystemServer中的main方法中&#xff0c;调用run方法。 private void run() { // Initialize native services.初始化服务&#xff0c;加载andro…...

Docker Macvlan网络创建及通信配置

环境说明 4: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000link/ether 7c:83:34:bc:e0:c2 brd ff:ff:ff:ff:ff:ffinet 10.5.1.33/24 brd 10.5.1.255 scope global dynamic bond0宿主机配置 变量配置 eth…...

删除文件要谨慎!如何在Linux中删除目录或文件

删除目录和文件是任何操作系统中最基本但最重要的功能之一。在Linux中,如果运行的是窗口环境,则可以使用文件管理器应用程序查找和删除文件。也许你是通过SSH远程登录的,或者你的Linux计算机没有安装GUI,或者你想对你要删除的内容有更多的控制权。与Linux中的任何东西一样,…...

使用 Docker 部署高可用 MongoDB 分片集群

使用 Docker 部署 MongoDB 集群 Mongodb 集群搭建 mongodb 集群搭建的方式有三种&#xff1a; 主从备份&#xff08;Master - Slave&#xff09;模式&#xff0c;或者叫主从复制模式。副本集&#xff08;Replica Set&#xff09;模式。分片&#xff08;Sharding&#xff09;…...

树莓派安装64位桌面版Ubuntu教程

事实证明不用显示屏没办法连接64位桌面版的22.04Ubuntu&#xff0c;虽然不用显示屏可以安装64位服务器版的22.04Ubuntu.或者虽然有但是我并不知道&#xff0c;我也不想再花时间去知道了&#xff0c;因为我已经花了3天时间了。 步骤&#xff1a; 1&#xff1a;下载64位22.04Ub…...

【sql注入】sql关卡1~4

前言&#xff1a; 靶场自取 level-1 测试注入点 POC: 1,1,1,1"",1/1,1/0 》存在注入点 爆破 POC: id-1andextractvalue(1,concat(0x7e,user(),0x7e))-- level-2 尝试注入点 POC1:admin POC2:admin POC3:adminandsleep(3)-- POC4: adminandif(1,1,0)0-- POC…...

【机器学习合集】模型设计之注意力机制动态网络 ->(个人学习记录笔记)

文章目录 注意力机制1. 注意力机制及其应用1.1 注意力机制的定义1.2 注意力机制的典型应用 2. 注意力模型设计2.1 空间注意力机制2.2 空间注意力模型2.3 通道注意力机制2.4 空间与通道注意力机制2.5 自注意力机制2.5 级联attention 动态网络1. 动态网络的定义2. 基于丢弃策略的…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...