一个简单好用的C语言单元测试框架-Unity

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

Unity简介:

Unity是一个用于C语言的轻量级单元测试框架。它由Throw The Switch团队开发,旨在简化嵌入式系统的单元测试。单元测试中单元的含义,单元就是人为规定的最小的被测功能模块,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。在实际项目中,单元测试往往由开发人员完成。
Unity的设计目标是易于使用、轻便、可移植,并能够在各种嵌入式和非嵌入式系统中运行。核心项目是一个 C 文件和一对头文件,允许将其添加到现有的构建设置中,而不会太麻烦。 可以使用任何想用的编译器,并且可以使用大多数现有的构建系统,包括 Make、CMake 等。

Unity简单使用方法:

1、下载unity框架

去GitHub下载,或者gti clone到本地,链接地址:unity。

Unity 本身非常小。 其他剩下的只是可选附加组件。 可以忽略它或在方便时使用它。 以下是项目中所有内容的概述。

  • src- 这是你关心的代码!此文件夹包含一个 C 文件和两个头文件。 这三个文件是 Unity。
  • docs- 在这里可以找到所有方便的文档。
  • examples- 这包含一些使用 Unity 的示例。
  • extras- 这些是 Unity 的可选附加组件,不属于核心项目。
  • test- 这就是 Unity 及其脚本的测试方式。 如果你只是使用Unity,你可能永远不需要进入这里。
  • auto- 在这里,你将找到有用的 Ruby 脚本,以简化你的测试工作流程。 它们完全是可选的,不需要使用 Unity。

2、使用unity框架

测试文件是 C 文件。 大多数情况下,将为每个要测试的 C 模块创建一个测试文件。 测试文件应包含 unity.h 和要测试的 C 模块的标头。

例如测试下面两个函数:

ProductionCode.c

#include "ProductionCode.h"

int Counter = 0;
int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; /* some obnoxious array to search that is 1-based indexing instead of 0. */

/* This function is supposed to search through NumbersToFind and find a particular number.
 * If it finds it, the index is returned.  Otherwise 0 is returned which sorta makes sense since
 * NumbersToFind is indexed from 1.  Unfortunately it's broken
 * (and should therefore be caught by our tests) */
int FindFunction_WhichIsBroken(int NumberToFind)
{
    int i = 0;
    while (i < 8) /* Notice I should have been in braces */
        i++;
        if (NumbersToFind[i] == NumberToFind) /* Yikes!  I'm getting run after the loop finishes instead of during it! */
            return i;
    return 0;
}

int FunctionWhichReturnsLocalVariable(void)
{
    return Counter;
}

ProductionCode.h

#ifndef  _PRODICTIONCODE_H_
#define  _PRODICTIONCODE_H_

extern int Counter;

int FindFunction_WhichIsBroken(int NumberToFind);
int FunctionWhichReturnsLocalVariable(void);

#endif

接下来,测试文件将包含测试例程函数。 setUp 函数可以包含你希望在每次测试之前运行的任何内容。 tearDown 函数可以包含你希望在每次测试后运行的任何内容。 这两个函数都不接受任何参数,也不返回任何内容。 如果不需要它们,将其设置为空。setUp() tearDown()

TestProductionCode.h


#include "ProductionCode.h"
#include "unity.h"

/* sometimes you may want to get at local data in a module.
 * for example: If you plan to pass by reference, this could be useful
 * however, it should often be avoided */
extern int Counter;

void setUp(void)
{
  /* This is run before EACH TEST */
  Counter = 0x5a5a;
}

void tearDown(void)
{
}

void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void)
{
  /* All of these should pass */
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(2));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1));
}

void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void)
{
  /* You should see this line fail in your test summary */
  TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34));

  /* Notice the rest of these didn't get a chance to run because the line above failed.
   * Unit tests abort each test function on the first sign of trouble.
   * Then NEXT test function runs as normal. */
  TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888));
}

void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void)
{
    /* This should be true because setUp set this up for us before this test */
    TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());

    /* This should be true because we can still change our answer */
    Counter = 0x1234;
    TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void)
{
    /* This should be true again because setup was rerun before this test (and after we changed it to 0x1234) */
    TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
}

void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void)
{
    /* Sometimes you get the test wrong.  When that happens, you get a failure too... and a quick look should tell
     * you what actually happened...which in this case was a failure to setup the initial condition. */
    TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

最后,在编写main函数,然后调用每个测试例程函数。 这实际上会触发每个测试例程函数运行,因此每个函数都有自己的调用非常重要。

/* AUTOGENERATED FILE. DO NOT EDIT. */
/*=======Automagically Detected Files To Include=====*/
#include "unity.h"
#include <setjmp.h>
#include <stdio.h>
#include "ProductionCode.h"

/*=======External Functions This Runner Calls=====*/
extern void setUp(void);
extern void tearDown(void);
extern void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void);
extern void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void);
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void);
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void);
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void);


/*=======MAIN=====*/
int main(void)
{
  UnityBegin("test/TestProductionCode.c");
  RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode);
  RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken);
  RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue);
  RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain);
  RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed);

  return (UnityEnd());
}

3、构建运行环境

创建一个目录 TDDUnityExample,在TDDUnityExample 目录下创建 CMakeLists.txt 文件。

# 最低CMake版本要求
cmake_minimum_required(VERSION 3.15)

#将Unity/src工作目录的源文件赋给UNITY_SRC_LIST
#将Tests工作目录的源文件赋给APP_SRC_DIR
aux_source_directory (Unity/src UNITY_SRC_LIST)
aux_source_directory (Tests APP_SRC_DIR)

# 项目名称
project(TDD_test)

# 头文件路径
include_directories(Unity/src)

#将所有源文件生成一个可执行文件
add_executable(TDD_test  ${APP_SRC_DIR} ${UNITY_SRC_LIST})
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

在 TDDUnityExample 下创建 Unity 目录,然后将Unity 框架源码中的 src 目录拷贝到 Unity目录中。

在 TDDUnityExample 下创建 Tests 目录,然后将第二点中举例的测试文件都放在 Tests 目录中。

在 TDDUnityExample 下创建 build 目录,然后在 build 目录下也创建一个 CMakeLists.txt 文件。

cmake_minimum_required (VERSION 2.8)

project (TDD_test)

add_subdirectory (Tests)

最后整体文件结构如下:

├── build
│   └── CMakeLists.txt
├── CMakeLists.txt
├── Tests
│   ├── ProductionCode.c
│   ├── ProductionCode.h
│   ├── TestProductionCode.c
│   └── TestProductionCode_Runner.c
└── Unity
    └── src
        ├── meson.build
        ├── unity.c
        ├── unity.h
        └── unity_internals.h

4、运行测试程序

在 build 目录下输入 cmake ..命令,会自动生成 Makefile 文件,然后输入make,就会自动编译生成可执行文件 TDD_test 在 TDDUnityExample /bin 下。

进入 TDDUnityExample /bin 下,输入./TDD_test

输出结果为:

test/TestProductionCode.c:0:test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode:PASS
test/TestProductionCode.c:33:test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken:FAIL: Expected 1 Was 0
test/TestProductionCode.c:0:test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue:PASS
test/TestProductionCode.c:0:test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain:PASS
test/TestProductionCode.c:61:test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed:FAIL: Expected 0x00001234 Was 0x00005A5A

-----------------------
5 Tests 2 Failures 0 Ignored 
FAIL

从结果来看第二个和第五个测试例程出现错误,错误原因也标记出来了。

5、常用断言

TEST_PASS(); /* 中止测试的其余部分, 但将测试计为通过 */
TEST_PASS_MESSAGE("message")

TEST_IGNORE(); /* 将测试用例标记为忽略, 但将测试计为通过 */
TEST_PASS_MESSAGE("message")
    
TEST_FAIL(); /* 中止测试的其余部分, 但将测试计为失败 */
TEST_FAIL_MESSAGE("message")
    
TEST_MESSAGE(""); /* 将消息输出 */

以上断言宏都是放在编写的测试函数中,TEST_IGNORE 一般放在函数的顶部,用来表示将测试用例忽略,其他宏可以放在函数的任意位置。

总结:

unity单元测试框架核心是一个 C 文件和一对头文件,特点是简洁易用轻量级可移植性支持测试断言等。其中有许多测试断言需要多了解多使用。

好了以上就是Unity单元测试框架的简易使用方法,有什么疑问和建议欢迎在评论区中提出,想要了解更多的Unity知识可以去官网上查看,官网上也有详细的教程和实例。文章来源地址https://www.toymoban.com/news/detail-813036.html

到了这里,关于一个简单好用的C语言单元测试框架-Unity的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Unity基础 - 封装一个好用的事件系统

    在游戏开发过程中,我们会大量使用事件系统。很多时候,比起直接调用对象组件的方法,使用事件触发将很大程度上降低系统的耦合度,从而实现更为优雅的系统设计。 封装一个好用的事件系统将对我们的开发起到很大的帮助。 本文将基于Unity提供的ScriptableObject和UnityEv

    2024年02月02日
    浏览(44)
  • unity 单元测试

    Created: February 23, 2023 11:11 PM Tags: C语言, stm32, 单元测试 为了方便在stm32上进行单元测试,需要在项目中导入unity框架以便于对项目的单元测试。本章节将简单介绍如何使用Unity进行单元测试,更加详细的内容可以移步Unity的GitHub。 没有安装git的同学可以直接上github下载源代码,

    2024年02月06日
    浏览(34)
  • Unity单元测试

    Unity单元测试是一个专门用于嵌入式单元测试的库, 现在简单讲下移植以及代码结构. 源码地址: GitHub - ThrowTheSwitch/Unity: Simple Unit Testing for C 1.我们只需要移植三个文件即可: unity.c, unity.h, unity_internals.h 2.然后添加需要测试的函数. 3.在main.c中添加两个空函数以及一个宏 废话就不

    2024年02月22日
    浏览(36)
  • linux环境编程(1): 实现一个单元测试框架-2

    在之前的文章中, 介绍了如何实现一个类似gtest的单元测试框架, 完整的项目代码可以参考这里: https://github.com/kfggww/cutest . 近期对cutest的实现做了一些修改, 包括: Test Suite的声明宏, 修改为TEST_SUITE 增加Test Suite的声明宏TEST_SUITE_WITH. 可传递Suite的init和cleanup函数, 在Suite中每个Cas

    2024年02月12日
    浏览(34)
  • Java开发手册之单元测试,软件测试端简单易用的SPI框架

    【推荐】编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。 B:Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。 C:Correct,正确的输入,并得到预期的结果。 D:Design,与设计文档相结合,来编写单元测试。 E:Error,强制错误信息输

    2024年04月25日
    浏览(48)
  • 如何使用PHPUnit编写一个PHP单元测试-简单的代码示例

    在软件开发过程中,单元测试是一种重要的测试方法,可以确保代码的质量和可靠性。在PHP开发中,也可以通过编写单元测试来验证代码的正确性。下面将介绍一些编写PHP单元测试的基本步骤和常用工具。 首先,你需要一个PHP单元测试框架,比如PHPUnit。PHPUnit是PHP社区最流行

    2024年02月04日
    浏览(56)
  • ​基于多种语言,使用Selenium实现自动化的常用单元测试框架

    Selenium是自动化网络应用程序的首选工具。Selenium支持基于Java、C#、PHP、Ruby、Perl、JavaScript和Python等多种编程语言的各种单元测试框架。这些框架用于在 Windows、MacOS 和 Linux 等不同平台的网络应用程序上执行测试脚本。任何成功的自动化流程都有赖于强大的测试框架,这些框架

    2024年01月21日
    浏览(54)
  • 【C C++开源库】适合单片机 嵌入式的C语言单元测试库_单片机 单元测试框架

    #define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((thres

    2024年04月25日
    浏览(49)
  • C语言单元测试框架——CUnit 安装(windows和Linux)及使用

    昨天把软件测试基础基本上看完了,因为我最近工作问题,需要着重研究下Cunit这个单元测试框架,上午把之前学的基础整理出来了。 刚刚研究了下Cunit除了基本 (Basic)接口,还有三个接口没使用过,我也会经量都尝试下。 下个星期我的任务是写一个墨水屏的驱动,测试的学

    2024年02月09日
    浏览(39)
  • 【Unity】教你如何使用Unity制作一个简单的跑酷游戏

    其实用Unity制作游戏并不难,如果你想学习,那我就建议你想从制作一个简单的跑酷游戏来找到兴趣,因为如果你一开始就一直学习一些没什么必要的语法,这样就会让你一开始就失去了信心,失去了学习Unity的动力,所以如果你先学习如何制作一个简单的跑酷地图,然后你就

    2024年02月21日
    浏览(57)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包