RT_Thread的测试框架使用及分析
来源:互联网 发布:java empty string 编辑:程序博客网 时间:2024/04/27 22:44
RT_Thread的测试框架使用及分析
为了行文的简单,RT_Thread将简称为RTT。
一个最简单的测试用例(不使用TestCase框架)
RTT的finsh组件,提供了非常强大的调试功能,我们可以将函数输出到finsh上,然后就可以在finsh中手动的调用这个函数,这一点非常的强大。可以说finsh是RTT的调试利器,善用finsh,可以极大的提高开发的效率。
关于finsh的详细的介绍,可以参考《RT_Thread实时操作系统编程指南》的 Finsh Shell系统一章,这里先只是简单的举一个例子。
在application.c中的最后添加如下代码
int testfunc(void){rt_kprintf("hello, rt-thread!\n");}#include <finsh.h>FINSH_FUNCTION_EXPORT(testfunc, just a test function);
不要忘记在rtconfig.h中使能 RT_USING_FINSH宏.
我们编写了名为 testfunc的函数,然后希望在finsh中挑用它,那么我们需要使用FINSH_FUNCTION_EXPORT宏带两个参数,第一个参数是函数名,第二个参数是对函数的说明,可以是任意字符串,用户可以根据自己的喜好编写,不过建议对函数做客观的说明或介绍。
FINSH_FUNCTION_EXPORT 会函数testfunc输出给finsh,这样finsh就会“知道”有一个函数名为testfunc。
接下来,重新编译工程,启动串口工具,比如putty,windows系统自带的超级终端,或者SecureCRT。
复位开发板,你就可以看到如下信息:
\ | /- RT - Thread Operating System / | \ 1.1.0 build Apr 15 2012 2006 - 2012 Copyright by rt-thread teamfinsh />
此时,按下Tab键,可以看到如下语句
--function:testfunc -- just a test functionlist_mem -- list memory usage informationlist_date -- list datehello -- say hello worldversion -- show RT-Thread version informationlist_thread -- list threadlist_sem -- list semaphone in systemlist_event -- list event in systemlist_mutex -- list mutex in systemlist_mailbox -- list mail box in systemlist_msgqueue -- list message queue in systemlist_mempool -- list memory pool in systemlist_timer -- list timer in systemlist_device -- list device in systemlist -- list all symbol in system--variable:dummy -- dummy variable for finshfinsh />
第一句就是我们刚刚编写的函数,左边是函数名,右边即函数说明。
接下来,在finsh上输入 t 然后按下Tab键,finsh会自动地为我们补全testfunc,然后我们手动输入 ()后回车,可以看到如下运行效果:
finsh />testfunc()hello, rt-thread! 0, 0x00000000finsh />
注:finsh跟linux下的shell很像,都具有tab键自动补全的功能,但是又有些不同,finsh的命令是C语言风格的,命令即函数调用语句。
可以看到,我们在finsh中成功的手动调用了刚刚编写的testfunc函数。这个特性在调试程序时非常有用。可见可以通过这种方式来编写一些测试程序,并通过finsh来手动的调用这些测试用例。
实际上,在正式的项目开发中,测试是非常重要的环节,是程序质量的重要保障。我们可能为此编写大量的测试用例,此时一个一个在finsh中手动的输入函数名来运行测试用例的方式显然后有些原始,这个工作没有任何技术含量,枯燥乏味且令人恼火,那么这种情况下,改怎么办呢?
别担心,RTT为我们提供了所谓的 测试用例(TestCase, 简称为TC) 框架。TC框架可以帮助我们依次,自动的调用多个测试用例函数。
下一节,我们将添加一个testfunc2函数,跟testfunc函数一起采用TC框架,首先准备两个测试用例代码(为了代码的清晰,我么将测试用例放在独立的c文件中).
在当前BSP主目录下,创建一个名为testcase的文件夹。
将下面代码保存为 testfunc1.c ,存放到testcase/下。
#include <rtthread.h>int testfunc1(void){rt_kprintf("hello, rt-thread! this is testfunc1\n");}#include <finsh.h>FINSH_FUNCTION_EXPORT(testfunc1, just a test function);
将下面代码保存为 testfunc2.c 存放到testcase/下。
#include <rtthread.h>int testfunc2(void){rt_kprintf("hello, rt-thread! this is testfunc2\n");}#include <finsh.h>FINSH_FUNCTION_EXPORT(testfunc2, just a test function);
编写基于TC框架的测试用例
1. 修改rtconfig.h
使能如下两个宏
#define RT_USING_TC#define RT_USING_FINSH
2.添加TC框架源码以及测试用例源码
因为TC测试框架需要如下这两个文件,
tc_comm.c
tc_comm.h
这两个文件位于RTT源码包examples/kernel/目录下,此目录下出这两个文件以外,还包含其他很多文件,那些文件是RTT官方提供基于TC框架的测试用例,它们用于测试RTT内核的基本功能。
这里,笔者要忍不住吐槽两句,当前RTT的文件放置仍然有些混乱,tc_comm.c和tc_comm.h不应该与测试用例放在一起。我们为其他的组件编写的测试用例放在什么地方呢?
将上面这两个文件复制到当前BSP目录下的testcase目录下。
将下面代码 testcase/SConscript文件
from building import *src = Glob("*.c")group = DefineGroup('testcase', src, depend = ['RT_USING_TC'])Return('group')
修改当前BSP目录下的SConstuct文件,添加如下代码
if GetDepend('RT_USING_TC'):objs = objs + SConscript(GetCurrentDir() + '/testcase/SConscript', variant_dir='build/tc', duplicate=0)
3. 修改 testfunc1.c 和 testfunc2.c
将 testfunc1.c 修改为:
#include <rtthread.h>#include "tc_comm.h"int testfunc1(void){rt_kprintf("hello, rt-thread! this is testfunc1\n");}#include <finsh.h>FINSH_FUNCTION_EXPORT(testfunc1, just a test function);static void _tc_cleanup(){tc_done(TC_STAT_PASSED);}int _tc_testfunc1(){/* 设置TestCase清理回调函数 */tc_cleanup(_tc_cleanup);testfunc1();/* 返回TestCase运行的最长时间 */return 100;}/* 输出函数命令到finsh shell中 */FINSH_FUNCTION_EXPORT(_tc_testfunc1, a dynamic thread example);
同样,将 testfunc2.c 修改为:
#include <rtthread.h>#include "tc_comm.h"int testfunc2(void){rt_kprintf("hello, rt-thread! this is testfunc2\n");}#include <finsh.h>FINSH_FUNCTION_EXPORT(testfunc2, just a test function);static void _tc_cleanup(){tc_done(TC_STAT_PASSED);}int _tc_testfunc2(){/* 设置TestCase清理回调函数 */tc_cleanup(_tc_cleanup);testfunc2();/* 返回TestCase运行的最长时间 */return 100;}/* 输出函数命令到finsh shell中 */FINSH_FUNCTION_EXPORT(_tc_testfunc2, a dynamic thread example);
4. 编译运行
在命令行下执行scons 编译,然后启动finsh,按下tab键,可以看到 testfunc1和testfunc2.
除此之外,还多出来三个函数,分别是
- tc_start
- tc_stop
- list_tc
在tc_comm.h中有这三个函数的原型,这三个函数就是TC框架提供给我们的函数,我们只需要执行 tc_start(“test”),TC框架就会自动的依次调用 testfunc1 和 testfunc2函数。效果如下所示。
finsh />tc_start("test") 805434376, 0x3001f408finsh />Run TestCase: testfunc1hello, rt-thread! this is testfunc1TestCase[testfunc1] passedRun TestCase: testfunc2hello, rt-thread! this is testfunc2TestCase[testfunc2] passedRT-Thread TestCase Running Done!finsh />
这里简要说明一下 tc_start(“test”)的含义,我们编写两个测试函数的函数名分别为
- testfunc1
- testfunc2
显然这两个函数具有共同的前缀字符串,这里我输入的是“test”, 当然你也可以输入 “testf”, “testfun”等等。
扩展阅读
关于Finsh Shell的更多介绍请参考《RT_Thread实时操作系统编程指南》 的“Finsh Shell系统”章。
运行RTT官方自带的TC用例
RTT的官方源码包中已经包含了一些测试用例,它们位于example/目录下。读者需要注意,只有example/kernel目录下的源码文件是基于TC的测试用例,其他子目录下的文件并不是基于TC框架框架编写的。
修改当前BSP目录下的SConstuct文件,将如下代码
if GetDepend('RT_USING_TC'):objs = objs + SConscript(GetCurrentDir() + '/testcase/SConscript', variant_dir='build/tc', duplicate=0)修改为
if GetDepend('RT_USING_TC'):objs = objs + SConscript((RTT_ROOT + '/example/kernel/SConscript', variant_dir='build/tc/kernel', duplicate=0)
编译运行,启动finsh后,按下TAB键,可以出现很多函数, 这些函数就是输出到Finsh上的测试用例。
你可以执行
tc_start(“thread”) 对kernel做线程相关的测试
tc_start(“timer”) 对kernel做定时器相关的测试
tc_start(“semahore”) 对kernel做信号量相关的测试
...等等
下一节将剖析RTT的TestCase框架源码。
TestCase框架原理分析
在example/kernel/下提供了一个tc_sample.c,这个是RTT官方提供的TC测试用例的样本代码。我们将研究此文件来分析TestCase框架。
TC框架所涉及到文件为
examples/kernel/tc_comm.c
examples/kernel/tc_comm.h
examples/kernel/tc_sample.c
其中tc_sample.c源码如下:
#include <rtthread.h>#include "tc_comm.h"static rt_thread_t tid = RT_NULL;static void sample_thread(void* parameter){rt_kprintf("I'm sample!\n");}static void sample_thread_cleanup(struct rt_thread *p){tid = RT_NULL;tc_done(TC_STAT_PASSED);}int sample_init(){tid = rt_thread_create("t",sample_thread, RT_NULL,THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);if (tid != RT_NULL){rt_thread_startup(tid);tid->cleanup = sample_thread_cleanup;}elsetc_stat(TC_STAT_END | TC_STAT_FAILED);return 0;}#ifdef RT_USING_TCstatic void _tc_cleanup(){/* lock scheduler */rt_enter_critical();/* delete thread */if (tid != RT_NULL){rt_kprintf("tid1 is bad\n");tc_stat(TC_STAT_FAILED);}/* unlock scheduler */rt_exit_critical();}int _tc_sample(){/* set tc cleanup */tc_cleanup(_tc_cleanup);sample_init();return 25;}FINSH_FUNCTION_EXPORT(_tc_sample, a thread testcase example);#elseint rt_application_init(){sample_init();return 0;}#endif
未完待续....
- RT_Thread的测试框架使用及分析
- rt_thread学习笔记(1)---rt_thread启动流程分析
- 关于软件测试及测试工具的使用现状分析
- Struts2框架使用及分析
- 一个精简的测试框架及使用示例
- 关于appium测试框架的调研及使用
- RT_Thread最新开发板RealBoard—LPC4088的介绍及编译环境的搭建和下载
- RT_Thread下的LWIP传递机制
- RT_Thread应用中遇到的各种问题
- 测试框架Mocha的使用
- mochajs测试框架的使用
- 【自动化测试】Pexpect自动化测试框架使用及实例
- 自动化测试框架:日志的分析
- 自动化测试框架:日志的分析
- 自动化测试框架:日志的分析
- Akka框架性能的简单测试分析
- iOS--SocketRocket框架的使用及测试服务器的搭建
- 测试框架分析
- SIGPIPE信号结束进程.
- 项目从 ArcEning 9.3 升级为 10.0 出现的错误
- 加拿大皇家制币厂发行虚拟货币MintChip
- ActiveMq 安装时,报 open sc manager failed 错误解决
- Java心得---封装、日期、数学等相关类
- RT_Thread的测试框架使用及分析
- VC/MFC实现写Excel文件
- 带有LOB字段的表迁移
- Jakarta log4j.xml に設定するログレベルの整理
- linux-3.2.7移植OK6410的SD卡驱动
- Implementing a new real-time scheduling policy for Linux
- error C2664 和 Add to Project不能用
- 设计模式的概念
- 标准2 维表问题