嵌入式--->ceeding(UT嵌入式自动化测试工具),使用过程详解(保姆级)

ceedling是针对C语言的核心测试框架,专用于嵌入式
环境:window10 x64
官方简易教程点击跳转
以下命令无特殊说明都是在cmd下执行的,本篇文章是基础的配置与使用,在具体工程中的技巧和使用见下篇

Ceedling介绍

  • Ceedling提供了一个简单的接口,用于配置从基础到复杂的项目结构。从而可以使用ceedling进行简单工程、有多个依赖库依赖项的工程、多个依赖工具工具的工程的测试代码构建;
  • Ceedling是基于unity的框架,是针对C语言的核心测试框架,专用于嵌入式的;
  • Ceedling是对RubyRake (make-ish)构建系统的扩展,Ceedling主要针对C语言中的测试驱动开发(Test-Driven Development),旨在整合CMock(生成模拟接口)unity(单元测试框架)CException(异常处理框架) 这三个很棒的开源项目。

搭建环境

1.安装Ruby

官网上下载安装Ruby,建议使用2.7.2版本,然后将其bin路径添加到系统环境变量PATH中,最后检测是否安装成功。

ruby -v #检测是否安装成功

2.安装Ceeding

ceedling是在ruby gem镜像源中的一个软件,我们打开命令窗口输入一下指令来在ruby的安装路径中添加ceedling组件,建议使用0.30.0版本,否则有可能出现预料范围之外的错误。

gem install ceedling --version=0.30.0  #安装0.30.0版本

3.安装gcc

为了在window平台下运行gcc命令我们需要 安装MinGW-w64下载MinGW-W64-install.exe
安装详细教程:一篇参考文章,安装过程中如果报错,可以尝试关闭防火墙和杀毒程序,或降低安装版本;安装一开始报错则可能是包不是最新的,重新下载一下试试;
安装过程中,进行如下选择。
在这里插入图片描述
安装完毕后同样将MinGW-w64安装目录下的bin路径加入 PATH中。最后检测是否安装成功。

gcc -v

4.安装gcov

使用pip命令需要安装python支持,之后pip命令来安装gcov,用于生成覆盖率报表。

pip install gcovr

ceedling使用过程

官方给了一些参考工程可供参考,使用如下命令就可以下载下来。

ceedling help  
ceedling examples #查看官方给的示例
ceedling example blinky #选择其中一个示例刨下来

1.创建测试项目树

ceedling支持使用命令创建项目树:

ceedling new test_ceedling	#test_ceedling工程名可以按你自己想要的取

创建的几个目录和文件介绍:

build:构建的测试程序存放目录,在执行测试之后自动生成,build存放了CMock文件,覆盖率报表等等

src:ceedling预留的源文件存放目录,这里我们将源文件放在了我们创建的src文件夹中,可以不使用此处的src作为源文件存放目录,但是这就需要在project.yml中对source进行修改

test:存放我们需要测试的C文件

project.yml:实际的项目文件,可以根据需要进行调整配置ceedling

2.查看与修改项目配置文件project.yml

  • 测试架构ceedling的核心文件是project.yml,它包含有项目源文件的路径,若没有使用默认路径,需要将project.yml中的paths稍作修改,替换成从我们的源文件路径:

    :paths:
    	:test:
    		- +:test/**
    		- -:test/support
    	:source:
    		- ../yourPath/balabala/**
    	:support:
    		- test/support
    	:libraries: []
    	:include:
        	- +:../../Stepper Motor/STM32F0
        	- +:../../Stepper Motor/STM32F0/Libraries/inc
    
  • 用于测试的文件需要有指定的开头,其配置语句如下,也就是我们测试文件命名为test_xxx.c

    :project:
    	:test_file_prefix: test_
    
  • 调用CMock生成mock文件解决依赖关系,需要引用对应的头文件并添加配置文件中的mock_前缀,也就是测试目标Add.c文件的被测试部分有调用Sub.c中的方法,就需要在测试文件中添加#include “mock_Sub.h”以虚拟Sub.c中的方法。

    :cmock:
    	:mock_prefix: mock_
    

    经过如上的简单配置就可以初步使用了,要使用具体的插件(plugin)还需要具体的配置哦😄

3.编写测试文件

  • 在上一步project.yml中配置的:test:目录下创建名为test_xxxx.c的文件,开始填充内容:
    一个空的参考模板如下,在运行每个测试之前调用setUp(),在运行每个测试之后调用tearDown()test_first是测试内容的主体

      #include "unity.h"
    
      void setUp(void){}		//
      void tearDown(void){}		//这两个函数必须包含
      
      void test_first(void)		//测试函数需要以test_开头,一个测试函数就是一个测试任务
      {
          //TO DO
      }
    
  • 为了更直观的展示测试流程,在src目录下添加了四个文件Add.cAdd.hSub.cSub.h,其中Add.c中的int Add(int a,int b)为被测试模块,在被测试模块中调用了Sub.c中的int Sub(int a,int b)方法

    //Add.c的内容
    #include "Add.h"
    #include "Sub.h"
    
    int Add(int a,int b)
    {
        //Sub(a,b);			//在(3).使用CMock构建虚拟库时取消注释,对Sub进行mock
        return a+b;
    }
    

    这里,在test目录下创建test_Add.c,开始修改其内容

    (1).添加被测试文件的头文件

     #include "Add.h"
    

    (2).添加测试语句

    test_first函数修改为test_Add

    void test_Add(void)
    {
        TEST_ASSERT_EQUAL_INT(5,Add(2,3));		//宏在unity.h中定义
    }
    

    至此我们就可以进行第一次测试了,在project.yml同级目录下执行如下命令

    ceedling test:all
    
    Test 'TestAdd.c'
    ----------------
    Generating runner for TestAdd.c...
    Compiling TestAdd_runner.c...
    Compiling TestAdd.c...
    Linking TestAdd.out...
    Running TestAdd.out...
    
    --------------------
    OVERALL TEST SUMMARY
    --------------------
    TESTED:  1
    PASSED:  1
    FAILED:  0
    IGNORED: 0
    

    (3).使用CMock构建虚拟库,使有依赖项的测试模块可以编译通过

    Add.c中引用了Sub.h并调用其Sub方法,这时候就需要使用CMock来虚拟Sub方法,才能使ceedling测试通过,在peoject.yml中关于CMock的配置语句:

    :cmock:
      :mock_prefix: mock_
    

    在测试文件加入对应的Mock头文件,需要知道的是只用添加被引用文件的对应头文件便,并添加mock_前缀,ceedling框架会自动为我们生成mock_xxx.h,以及对应的mock_xxx.c并且实现其方法,不过这些方法在使用前,需要我们手动去调用,给定预期的参数和返回值才能正常使用,经过一系列的修改文件就成了下面的样子

    #include "unity.h"
    #include "Add.h"
    #include "mock_Sub.h"					//Sub.h对应的Mock文件,测试执行后自动生成
    
    void setUp(void){}
    void tearDown(void){}
    
    void test_Add(void)
    {
        Sub_CMockExpectAndReturn(0,2,3,5);	//Sub函数对应的Mock函数
        TEST_ASSERT_EQUAL_INT(5,Add(2,3));
    }
    

4.生成覆盖率报表

  • 生成覆盖率报表是在生产环节中是不可少的

    (1).激活gcov

    project.yml中添加对gcov插件的使用

    :plugins:
    	:enabled:
    		- gcov
    

    之后可以在bulid/artifacts/gcov目录下查看覆盖率测试结果

    (2).gcov参数优化

    生成报表提供更多的参考信息

    :gcov:
      :reports:
       - Cobertura
        - HtmlDetailed
        - SonarQube
        - Badges
      :gcovr:
        :html_medium_threshold: 75
        :html_high_threshold: 90
        :xml_pretty: true
    

    (3).进行测试

    ceedling gcov:all utils:gcov
    

附录

工程配置文件project.yml

首先需要对yaml语法有一个基础的认识 菜鸟教程-点击跳转

project.yml注意与约定
project.yml中应该至少包含如下3个对象

 :project
 	:build_root :  
 		***
 :paths
 	:source : 
 		***
 	:test : 
 		***

各个对象的解释

project

对象属性功能默认值
projectuse_exceptions构建环境,异常处理使用CExceptionsTRUE
projectbulid_root生成文件的目录none
projectuse_mocks构建环境,异常处理使用CMockTRUE
projectuse_test_preprocessor这个选项允许Ceedling处理包含条件编译语句(例如#ifdef)的测试文件
和将要模拟的包含条件预处理器语句、宏和头文件
FALSE
projectuse_preprocessor_directivesuse_test_preprocessor置TRUE才可使用此项,
置TRUE后宏将将展开为C代码
FALSE
projectuse_deep_dependencies这个选项允许适当的增量构建操作同时发生在测试执行和发布构建中。FALSE
projectgenerate_deep_dependenciesuse_deep_dependencies置TRUE此项才可使用
此项生成深度依赖项,以避免额外的构建步骤
TRUE
projecttest_file_prefix测试文件的前缀test_
projectoptions_paths读取其他yml文件的路径,并在运行时合并这些路径中的项目配置[ ] (empty)
projectrelease_build置TRUE一个发行版本的Rake任务将被执行FALSE

release_bulid

对象属性功能默认值
release_bulidoutput输出的二进制文件名称project.out
release_buliduse_assembly在项目树中有汇编代码时,置TRUE时Ceedling会生成指定目录并使用汇编工具FALSE
release_buildartifacts有选择地复制文件可以防止偶然的构建工具不必要地出现在artifacts 目录中[ ] (empty)

paths

对象属性功能默认值
pathstest测试文件存放的目录[ ] (empty)
pathssource工程代码,需要被测试的代码存放位置[ ] (empty)
pathssupport支持单元测试的文件存放位置,一般目录为test/support[ ] (empty)
pathsinclude一些不存在于源搜索路径中的头文件,在这里进行添加[ ] (empty)
pathsllibraries添加链接时要包含的库路径集合[ ] (empty)

extension

对象属性功能默认值
extensionheaderC头文件.h
extensionsourceC文件 (无论是源文件还是测试文件).c
extensionassembly汇编文件.s
extensionobjectC和汇编文件输出的*.o文件输出目录.o
extensionexecutable目标硬件上可执行的二进制文件.exe/.out
extensiontestpass测试结果文件.pass
extensiontestfail测试结果文件.fail
extensiondependenciesgcc预处理器生成的包含make-style依赖的文件.d

defines

添加公共定义

对象属性功能默认值
definestest1.对包含条件编译的测试文件有效
[ ] (empty)
definestest_preprocess如果project:use_test_preprocessor或project:use_deep_dependencies置TRUE,gcc可能需要一些定义来处理预处理文件,用来mock和解决深度依赖的的问题[ ] (empty)
defines<test_name>为指定的test_name定义替换标准的test定义[ ] (empty)

如下test_foo_config将拥有FOO_SPECIFIC_CONFIG定义,其他tests都不会拥有

:defines:    
	:test:      
  		- FOO_STANDARD_CONFIG    
	:test_foo_config:      
		- FOO_SPECIFIC_CONFIG

defult

对象属性功能默认值
defultrelease定义发布构建二进制文件 所需的内容[ ] (empty)
defultrelease如果设置了project:use_deep_dependencies,那么由于深度依赖,gcc预处理器可能需要用符号定义来正确地预处理增量发布而构建的文件。[ ] (empty)
defultuse_test_definition当使用此选项时,将把-D<test_name>标志添加到构建选项中。FALSE

libraries

引入特定的库

对象属性功能默认值
librariestest链接时注入到测试文件中的库文件[ ] (empty)
librariesrelease链接时发布版本的库文件目录,以动态依赖构建[ ] (empty)
librariessystem这里添加的库将被注入到发布版和测试中。
例如,如果指定-lm,可以包含数学库。
在:flag前缀没有为其他库指定-l时,仅需要-m就可添加数学库。
[ ] (empty)
librariesflag为每个库添加指定参数
librariespath_flag为每个库路径添加指定的参数
:libraries:  :placement: :end  :flag: "-l${1}"  :path_flag: "-L ${1}"  :system: []    # for example, you might list 'm' to grab the math library  :test: []  :release: []

flag

配置添加每个文件的编译和链接目标

对象属性功能默认值
flagrelease[:compile] or [:link] flags for release build
flagtest[:compile] or [:link] flags for release build
使用时注意的点:
1.文件说明符不包含路径和文件后缀2.文件说明符区分大小写3.用引号括起来,就可以用正则表达式来表达文件说明符4.`*`表示所有文件
:flags:  :release:    :compile:      :main:       # add '-Wall' to compilation of main.c        - -Wall      :fan:        # add '--O2' to compilation of fan.c        - --O2      :'test_.+':   # add '-pedantic' to all test-files        - -pedantic      :*:          # add '-foo' to compilation of all files not main.c or fan.c        - -foo  :test:    :compile:      :main:       # add '--O1' to compilation of main.c as part of test builds including main.c        - --O1    :link:      :test_main:  # add '--bar --baz' to linking of test_main.exe        - --bar        - --baz

import

添加附加的配置文件

:import:  - path/to/config.yml  - path/to/another/config.yml

cmock

对虚拟模块工具CMock进行配置

对象属性功能默认值
cmockenforce_strict_ordering如果预期的调用顺序与源顺序不相同,则测试将失败TRUE
cmockmock_path生成的mock路径bulid//tests/mocks
cmockdefines定义的符号只会用来编译CMock生成的C代码[ ] (empty)
cmockverbosity冗长级别默认为ceedling的冗长级别
cmockplugins指定cmock所需要的附加插件
cmockinlcude指定cmock的包含目录

宏定义的使用

这一部分在对已经存在的方法进行测试时尤为重要,如下就定义了全局宏UNIT_TESTWIN32,我们就可以用这些宏进行条件编译了

:defines:
  # in order to add common defines:
  #  1) remove the trailing [] from the :common: section
  #  2) add entries to the :common: section (e.g. :test: has TEST defined)
  :common: &common_defines 
    - UNIT_TEST
    - WIN32
  :test:
    - *common_defines
    - TEST
    - WIN32
  :test_preprocess:
    - *common_defines
    - TEST

其他

工具/插件/异常处理这里不再列出,详见tools/pluginsc/exception

关于gcov覆盖率报表生成失败

  1. 确定安装好了gcov,执行了正确的命令,查看配置,详见上文
  2. 必须是引用测试文件的.h文件,再对.c文件中的方法进行测试,一次直接引用.c文件导致未能生成覆盖率报表,至于破坏了原来文件的隔离性(所测试函数不提供给外部使用,是用static修饰的),只需要用宏进行条件编译就好了,宏的定义子project.yaml中的define中,具体的使用见上文

参考链接

1.ceedling社区文章


本文作者 @CSDN arize 未经授权禁止转载

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值