草庐IT

cunit基于Linux单元测试环境搭建

July-Mao 2023-04-10 原文

1.下载linux下的cunit的源码包下载地址:https://sourceforge.net/projects/cunit/files/latest/download

2.在linux下解压安装包CUnit-2.1-3.tar.bz2,解压命令如下tar -zxvf CUnit-2.1-3.tar.bz2

3.进入到/home/mf/CUnit-2.1-3目录,执行如下命令,安装源码包:

root@ubuntu:/home/mf/CUnit-2.1-3# aclocal
aclocal: warning: autoconf input should be named ‘configure.ac’, not ‘configure.in’
root@ubuntu:/home/mf/CUnit-2.1-3# autoconf
root@ubuntu:/home/mf/CUnit-2.1-3# automake
如果在automake过程中有文件丢失,则执行下面命令:automake --add-missing
root@ubuntu:/home/mf/CUnit-2.1-3# chmod u+x configure
root@ubuntu:/home/mf/CUnit-2.1-3#./configure --prefix=$HOME/local
(./configure --prefix 后面加路径可以需要你输入要安装的目录,目录的格式举例如下:/local
这里我是直接./configure,默认路径)
root@ubuntu:/home/mf/CUnit-2.1-3#make
root@ubuntu:/home/mf/CUnit-2.1-3#make install
(到这里位置,我们的cunit的源码库就安装好啦)

4.准备测试脚本,验证

这里我准备了4个文件:Main.c test.c testcase.c Makefile
放在Linux 下面新建的 root@ubuntu:/home/mf/Desktop/cunittest目录下

Main.c的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "Basic.h"

extern void AddTests(void);

int main(int argc, char* argv[])
{
    CU_BasicRunMode mode = CU_BRM_VERBOSE;
    CU_ErrorAction error_action = CUEA_IGNORE;
    int i;
    //标准库输出 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。
    setvbuf(stdout, NULL, _IONBF, 0);
    for (i=1 ; i<argc ; i++) {
        if (!strcmp("-i", *argv)) {
            //错误发生时继续执行(默认)
            error_action = CUEA_IGNORE;
        }
        else if (!strcmp("-f", *argv)) {
            //错误发生时应系统停止
            error_action = CUEA_FAIL;
        }
        else if (!strcmp("-A", *argv)) {
            //错误发生时系统应退出(EXIT)
            error_action = CUEA_ABORT;
        }
        else if (!strcmp("-s", *argv)) {
            //只会输出错误信息
            mode = CU_BRM_SILENT;
        }
        else if (!strcmp("-n", *argv)) {
            //结果会输出基本信息,包括失败以及测试运行的总体状况
            mode = CU_BRM_NORMAL;
            
        }
        else if (!strcmp("-v", *argv)) {
            //输出测试运行的详细信息
            mode = CU_BRM_VERBOSE;
        }
        else if (!strcmp("-e",*argv)) {
            return 0;
        }
        else {
            printf("\nUsage:BasicTest [options]\n\n"
            "Options:-i ignore framework errors [default].\n"
            " -f fail on framework error.\n"
            " -A abort on framework error.\n\n"
            " -s silent mode - no output to screen.\n"
            " -n normal mode - standard output to screen.\n"
            " -v verbose mode - max output to screen [default].\n\n"
            " -e print expected test results and exit.\n"
            " -h print this message and exit.\n\n");
            return 0;
    }
}
//CU_initialize_registry  registry初始化//用户在调用任何其他CUnit函数之前调用本函数,如果不这样做可能会导致系统崩溃。
if (CU_initialize_registry()) {
    printf("\nInitialization of Test Registry failed.");
}
else {
        AddTests();
        //CU_basic_set_mode()设置运行模式
        CU_basic_set_mode(mode);
        //CU_set_error_action设置错误发生时,系统的行为
        CU_set_error_action(error_action);
        //CU_basic_run_tests  运行Tests  Basic Mode   基本扩展编程方式  非交互式
        printf("\nTests completed with return value %d.\n",CU_basic_run_tests());
        // registry释放
        CU_cleanup_registry();
    }
    return 0;
}
test.c 的代码如下:
/**
*file:test.c
**/
int maxi(int i,int j)
{
    return i>j?i:j;
}
testcase.c 的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <CUnit/CUnit.h>
#include <CUnit/Automated.h>
#include <CUnit/TestDB.h>
/**//*---- functions to be tested ------*/
extern int maxi(int i , int j);

/**//*---- test cases ------------------*/
void testIQJ(void)
{
    //断言相等比较
    CU_ASSERT_EQUAL(maxi(1,1),1);
    CU_ASSERT_EQUAL(maxi(0,-0),0);
}
void testIGJ(void)
{
    CU_ASSERT_EQUAL(maxi(2,1),2);
    CU_ASSERT_EQUAL(maxi(0,-1),0);
    CU_ASSERT_EQUAL(maxi(-1,-2),-1);
}
void testILJ(void)
{
    CU_ASSERT_EQUAL(maxi(1,2),2);
    CU_ASSERT_EQUAL(maxi(-1,0),0);
    CU_ASSERT_EQUAL(maxi(-2,-1),-1);
}
CU_TestInfo testcases[] = {
    {"Testing i equals j:",testIQJ},
    {"Testing i greater than j:",testIGJ},
    {"Testing i less than j:", testILJ},
    CU_TEST_INFO_NULL
};
/**//*---- test suites ------------------*/
int suite_success_init(void)
{ return 0; }
int suite_success_clean(void)
{ return 0; }

//需要运行的test case
CU_SuiteInfo suites[] = {
    {"Testing the function maxi:",suite_success_init,suite_success_clean, NULL, NULL,testcases},
    CU_SUITE_INFO_NULL
};
/*cunit运行环境设置*/
void AddTests(void)
{
    //1.CU_get_registry  CU_register_suites其他一些关于注册的内部函数,主要用于内部和测试的目的
    assert(NULL != CU_get_registry());
    assert(!CU_is_test_running());
    //注册suites
    if(CUE_SUCCESS != CU_register_suites(suites)){
            fprintf(stderr, "Register suites failed - %s ", CU_get_error_msg());
    exit(EXIT_FAILURE);
    }
}
Makefile的代码如下:
INC=-I/usr/local/include/CUnit
LIB=-L/usr/local/lib
all:Main.c test.c testcase.c
	gcc -o test $(INC) $(LIB) $^ -lcunit
clean:
	-rm -rf *.o test

Makefile文件说明:

(1)INC=填写的是cuint的头文件的目录
(2)LIB=填写的是cunit的lib库的目录
(3)编译命令连接到头文件和lib库 生成可执行文件test
gcc -o test $(INC) $(LIB) $^ -lcunit

5.在linux的下面/home/mf/Desktop/cunittest目录执行make命令

root@ubuntu:/home/mf/Desktop/cunittest# make
此时出现了如下错误:没有找到lib库

解决如下:

(1)进入lib库的地址查看,cunit的lib库确实安装没有问题
(2)发现没有动态链接, 还需要设置动态库所在的位置
添加设置一个环境变量: export LD_LIBRARY_PATH=/usr/local/lib,操作如下:

  • 打开profile文件添加环境变量
    root@ubuntu:/etc# gedit /root/.profile
  • 添加好后记得 source /root/.profile
  • 修改完毕后,再次执行make,生成一个可执行文件,test

6.执行可执行文件

root@ubuntu:/home/mf/Desktop/cunittest# ./test
出现如下报错:

这里的段错误,程序内存出了问题,使用gdb方式进行调试,步骤如下:

  • 默认coredump不会保存在磁盘上,需要执ulimit -c unlimited才可以
    root@ubuntu:/home/mf/Desktop/cunittest# ulimit -c unlimited
  • 然后要 指定一下coredump的路径和格式:
    root@ubuntu:/home/mf/Desktop/cunittest#echo “/tmp/core-%e-%p” > /proc/sys/kernel/core_pattern
  • 重新make,在执行./test后就会产生一个coredump了
  • 进入coredump文件的目录
  • 开启gdb调试
    root@ubuntu:/tmp#gdb test.o /tmp/core-test-104138
    这里显示导致错误的是signal SIGSEGV信号,一般都是数组越界、死循环或者对空容器进行某些操作导致的。这里想到程序编译的时候出现的警告信息,
    继续(gdb) bt 可以看到是CU_register_suites(suites)这个函数出了问题,
    函数本身应该没有错误,可能是传给他从参数 有问题,就是那个suites,该参数构建的代码如下:
CU_SuiteInfo suites[] = {
    {"testSuite1", suite_success_init, suite_success_clean, testcase },
    CU_SUITE_INFO_NULL
};

这个CU_SuiteInfo的数组没有构建正确,该结构有6个成员,但我们定义的时候只有4个成员,直接修改为(以上提供的testcase.c脚本代码已经是修改后正确的代码)

CU_SuiteInfo suites[] = {
    {"testSuite1", suite_success_init, suite_success_clean,NULL, NULL, testcase },
    CU_SUITE_INFO_NULL
};

7.问题解决后,我们在make,生成一个新的test可执行文件,直接./test运行,就会标准输出的方式,在界面输出测试结果啦(后面也可以改为xml方式显示测试结果到网页)

有关cunit基于Linux单元测试环境搭建的更多相关文章

  1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  2. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  3. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  4. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  5. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  6. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  7. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  8. ruby-on-rails - 如何使辅助方法在 Rails 集成测试中可用? - 2

    我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel

  9. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  10. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

随机推荐