使用Glib中测试框架对C代码进行单元测试

这篇具有很好参考价值的文章主要介绍了使用Glib中测试框架对C代码进行单元测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++项目的测试框架比较常见的是Google的gtest(前文CMake项目使用ctest+gtest进行单元测试有使用实例介绍gtest,感兴趣的读者可以去看看),也有一些其它框架,比如Boost中的测试框架。这些框架虽然也可以测试C代码,但是如果在一个纯C项目中引入这些的框架,则需要使用C++编译器。那有没有纯C的测试框架呢?

当然有。

如果是进行纯C项目开发的话,各个平台的开发套件并没有像C++那样实现一个标准的STL库供开发人员使用,这就需要自己定义各种常见的数据结构,比如链表,数组,字典,字符串的处理,队列等等,也许每写一个项目就需要重复造这些轮子,甚至一个大项目中就重复造了不少这样的轮子。为了避免重复造轮子,推荐使用glib库,它不仅提供了前述数据结构,还提供了不少其它功能,包括测试框架,感兴趣的读者可以去官网了解,下面简单介绍一下GLib库。

一、GLib简介

在Windows上做开发可能很少甚至没有听过GLib库,但是在Linux下,它却是一个非常重要的库,Linux下的著名桌面GUI GNOME的基石就是它,GNOME是使用GTK开发的,而GTK的底层库就是GLib。

glib库官网:https://developer.gnome.org/glib/,按官网的介绍:

GLib是一个通用的,跨平台的实用库,它提供了许多有用的数据结构,宏,类型转换,字符串实用库,文件实用库,一个抽象的主循环等等。

它是使用的LGPL许可发布的,可以在Unix、Linux、Windows、MacOS平台上运行。

二、使用GLib的g_test框架

为了避免与Google的gtest混淆,GLib的测试框架写为g_test

g_testgtest一样需要在使用前进行初始化:

g_test_init(&argc, &argv, NULL);

然后注册测试用例,这里介绍常见的三种方式:

  1. 无输入参数的测试用例
    使用g_test_add_func函数注册,原型为:
typedef void (*GTestFunc)        (void);
void    g_test_add_func                 (const char     *testpath,
                                         GTestFunc       test_func);
  1. 有输入参数的测试用例
    使用g_test_add_data_func函数注册,原型为:
typedef const void *gconstpointer;
typedef void (*GTestDataFunc)    (gconstpointer user_data);
void    g_test_add_data_func            (const char     *testpath,
                                         gconstpointer   test_data,
                                         GTestDataFunc   test_func);

user_data就是输入的测试参数

  1. 复杂的,需要在测试前进行数据准备,测试后进行清理的测试用例
    使用宏g_test_add来注册,原型为:
#define g_test_add(testpath, Fixture, tdata, fsetup, ftest, fteardown) \
					G_STMT_START {			\
                                         void (*add_vtable) (const char*,       \
                                                    gsize,             \
                                                    gconstpointer,     \
                                                    void (*) (Fixture*, gconstpointer),   \
                                                    void (*) (Fixture*, gconstpointer),   \
                                                    void (*) (Fixture*, gconstpointer)) =  (void (*) (const gchar *, gsize, gconstpointer, void (*) (Fixture*, gconstpointer), void (*) (Fixture*, gconstpointer), void (*) (Fixture*, gconstpointer))) g_test_add_vtable; \
                                         add_vtable \
                                          (testpath, sizeof (Fixture), tdata, fsetup, ftest, fteardown); \
					} G_STMT_END

实际上它是使用函数g_test_add_vtable来注册的:

typedef void (*GTestFixtureFunc) (gpointer      fixture,
                                  gconstpointer user_data);
void    g_test_add_vtable               (const char     *testpath,
                                         gsize           data_size,
                                         gconstpointer   test_data,
                                         GTestFixtureFunc  data_setup,
                                         GTestFixtureFunc  data_test,
                                         GTestFixtureFunc  data_teardown);

user_data是输入的测试参数,data_setup是测试前的数据准备函数,data_test是正式的测试用例函数,data_teardown是测试完后做善后处理的函数。

每一个测试用例都需要一个路径testpath,且不能重复。

三、实例

main.c源码:

#include <glib.h>

typedef struct A
{
    int v;
} A;

void test()
{
    g_print("test\n");
}

void foo(gconstpointer test_data)
{
    A* a = (A*)test_data;
    g_print("A.v = %d\n", a->v);
}

/* run a test with fixture setup and teardown */
typedef struct
{
    guint seed;
    guint prime;
    gchar *msg;
} Fixturetest;

static void
fixturetest_setup(Fixturetest *fix,
                  gconstpointer test_data)
{
    g_assert_true(test_data == (void *)0xc0cac01a);
    fix->seed = 18;
    fix->prime = 19;
    fix->msg = g_strdup_printf("%d", fix->prime);
}

static void
fixturetest_test(Fixturetest *fix,
                 gconstpointer test_data)
{
    guint prime = g_spaced_primes_closest(fix->seed);
    g_assert_cmpint(prime, ==, fix->prime);
    prime = g_ascii_strtoull(fix->msg, NULL, 0);
    g_assert_cmpint(prime, ==, fix->prime);
    g_assert_true(test_data == (void *)0xc0cac01a);
}

static void
fixturetest_teardown(Fixturetest *fix,
                     gconstpointer test_data)
{
    g_assert_true(test_data == (void *)0xc0cac01a);
    g_free(fix->msg);
}

int main(int argc, char **argv)
{
    gchar *base_name = g_path_get_basename(argv[0]);
    g_set_prgname(base_name);
    g_free(base_name);

    g_log_set_debug_enabled(TRUE);
    g_debug("start test...");

    A a;
    a.v = 100;

    g_test_init(&argc, &argv, NULL);
    g_test_add_func("/t", test);
    g_test_add_data_func("/td", &a, foo);

    g_test_add("/t1", Fixturetest, (void*)0xc0cac01a, fixturetest_setup, fixturetest_test, fixturetest_teardown);
    int ret = g_test_run();
    g_message("A:%d", a.v);
    return ret;
}

CMakeLists.txt源码:

cmake_minimum_required(VERSION 3.12.0)
project(demo VERSION 0.1.0)

include(CTest)

enable_testing()

add_executable(${PROJECT_NAME} main.c)
find_package(PkgConfig REQUIRED)
pkg_check_modules (GLIB2 REQUIRED IMPORTED_TARGET glib-2.0>=2.70)
target_link_libraries(${PROJECT_NAME} PkgConfig::GLIB2)

message(STATUS "GLIB2_INCLUDE_DIRS: ${GLIB2_INCLUDE_DIRS}")
message(STATUS "GLIB2_LIBRARY_DIRS: ${GLIB2_LIBRARY_DIRS}")
message(STATUS "GLIB2_LIBRARIES: ${GLIB2_LIBRARIES}")

add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME})

运行结果:
使用Glib中测试框架对C代码进行单元测试

使用CTest测试结果:

使用Glib中测试框架对C代码进行单元测试

Glib还有很多非常强大的功能,感兴趣的读者可以去深究!文章来源地址https://www.toymoban.com/news/detail-421086.html

到了这里,关于使用Glib中测试框架对C代码进行单元测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 进行性能压力测试的原因、目的和好处

    性能压力测试是指在模拟高负载、高并发情况下对软件系统进行测试,以衡量系统在实际使用过程中的性能表现。这些测试可以为生产环境中的应用程序提供关键数据,并帮助开发人员从根本上了解系统的实际性能。在本文中,我们将探讨进行性能压力测试的原因、目的和好

    2024年02月10日
    浏览(79)
  • C# 中的单元测试,如何使用单元测试进行程序测试和调试?

    单元测试是一种软件测试方法,用于测试单个功能或方法是否按预期工作。在 C# 中,可以使用 .NET 框架中的单元测试工具来编写和运行单元测试。 下面是使用 Visual Studio 内置的单元测试框架来创建一个简单的单元测试的步骤: 在 Visual Studio 中创建一个新的类库项目。 在新项

    2024年02月15日
    浏览(63)
  • 使用phpunit进行单元测试

    本教程假定您使用 PHP 8.1 或 PHP 8.2。您将学习如何编写简单的单元测试以及如何下载和运行 PHPUnit. PHPUnit 10 的文档 在这。 1.PHP 存档 (PHAR) 我们分发了一个 PHP存档(PHAR),其中包含使用PHPUnit 10所需的一切 。只需从这里 下载 并使其可执行: 2.Composer 您可以使用 Composer 将 PHPU

    2024年02月12日
    浏览(38)
  • Go单元测试及框架使用

    建议Go 语言推荐测试文件和源代码文件放在一块,测试文件以 _test.go 结尾。 函数名必须以 Test 开头,后面一般跟待测试的函数名 参数为 t *testing.T 简单测试用例定义如下: 在goland中,编写好方法后,右键Generate-Test for funtion, 可自动生成单元测试代码 生成的代码如下: 需要

    2024年02月09日
    浏览(48)
  • 进行压力测试的目的是什么?重要性体现在哪?

    进行压力测试的目的是什么?重要性体现在哪?压力测试是通过施加一定压力或负荷于测试对象,以评估其结构、性能和可靠性的过程。它可以是静态压力测试,即施加一定压力并持续一段时间,也可以是动态压力测试,即施加变化的压力或冲击负荷。压力测试通常通过测量

    2024年02月11日
    浏览(39)
  • 特性介绍 | MySQL 测试框架 MTR 系列教程(二):进阶篇 - 内存/线程/代码覆盖率/单元/压力测试

    作者:卢文双 资深数据库内核研发 序言: 以前对 MySQL 测试框架 MTR 的使用,主要集中于 SQL 正确性验证。近期由于工作需要,深入了解了 MTR 的方方面面,发现 MTR 的能力不仅限于此,还支持单元测试、压力测试、代码覆盖率测试、内存错误检测、线程竞争与死锁等功能,因

    2024年02月03日
    浏览(50)
  • 如何使用PowerMock进行单元测试

    原博文:如何使用PowerMock进行单元测试 (techdatafuture.com) 持续更新 PowerMock是一个用于增强JUnit和TestNG的单元测试框架,它允许开发者在单元测试中模拟和修改代码中的静态方法、私有方法和构造函数。PowerMock基于Mockito和EasyMock,为Java开发者提供了一种更灵活、强大的测试工具

    2024年02月16日
    浏览(48)
  • 如何使用Jest进行单元测试

    Jest 是一种流行的 JavaScript 测试框架,它具有易用性和高效性。Jest 支持测试各种 JavaScript 应用程序,包括 React、Vue、Node.js 等。在本文中,我们将介绍如何使用 Jest 进行单元测试。 ## 1. 安装 Jest 首先,我们需要在项目中安装 Jest。可以使用 npm 或 yarn 安装 Jest: ``` npm install

    2024年02月10日
    浏览(40)
  • 使用Simulink Test进行单元测试

    本文摘要:主要介绍如何利用Simulink Test工具箱,对模型进行单元测试。内容包括,如何创建Test Harness模型,如何自动生成excel格式的测试用例模板来创建测试用例,如何手动填写excel格式的测试用例模板来手动创建测试用例。 单元测试的目的 创建完模型后,我们需要验证模型

    2024年02月16日
    浏览(42)
  • 使用 AssertJ 进行单元测试的提示

    单元测试已成为开发的标准部分。许多工具可以以许多不同的方式用于它。本文演示了一些提示,或者说,对我来说效果很好的最佳实践。 在本文中,您将了解 如何使用 JUnit 和 Assert 框架编写干净且可读的单元测试 在某些情况下如何避免假阳性测试 编写单元测试时应避免的

    2024年04月13日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包