Cunit单元测试是如何实现的?

发表于:2022-12-14 10:07

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:bdy    来源:博客园

  1.CUnit介绍:
   CUnit是完成测试的自动化工具,编写一定的代码就可以完成对工程的单元测试,包含N个suit,每个suit下面又有很多test。
  2.工具准备:
  a) CUnit的库及头文件
  b)Eclipse(配置了CDT---支持C/C++)
  c) 编译器MinGW或者安装cygwin来配置gcc。
  3.编写项目:
  下面以一个测试maxi函数为例进行介绍CUnit是如何进行自动化单元测试的。
  首先工程需要如下三个文件:
  test.c:表示需要测试的函数。
  int maxi(int x, inty)
  {
      if(x > y)
      {
           return  x;
      }
      else
      
      return  y;
  }
  Testcase.c:表示测试用例
  #include<stdio.h>
  #include<assert.h>
  #include<stdlib.h>
  #include"Automated.h"
  #include"CUnit.h"
  #include"TestDB.h"
  extern  int  maxi(inti, int  j);
  void  testILJ()
  {
      CU_ASSERT_EQUAL(maxi(1, 2), 2);
      CU_ASSERT_EQUAL(maxi(-1, 0), 0);
      CU_ASSERT_EQUAL(maxi(-2, -1), -1);
  }
  void  testIQJ()
  {
      CU_ASSERT_EQUAL(maxi(1, 1), 1);
      CU_ASSERT_EQUAL(maxi(0, -0), 0);
  }
  void  testIGJ()
  {
      CU_ASSERT_EQUAL(maxi(2, 1), 2);
      CU_ASSERT_EQUAL(maxi(0, -1), 0);
      CU_ASSERT_EQUAL(maxi(-1, -2), -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
  };
  int  suite_success_init(void)
  {
      return  0;
  }
  int  suite_success_clean(void)
  {
      return  0;
  }
  CU_SuiteInfo suites[] = //一个测试suite init-->testcase-->clean
  {
      {"Testing the functionmaxi:", suite_success_init, suite_success_clean, testcases},
      CU_SUITE_INFO_NULL
  };
  void  AddTests(void)
  {
      assert(NULL != CU_get_registry());
      assert(!CU_is_test_running());
      if(CUE_SUCCESS  != CU_register_suites(suites))  //注册测试suite
      {
          fprintf(stderr, "Register suites failed - %s ", CU_get_error_msg());
          exit(EXIT_FAILURE);
      }
  }
  main.c:函数入口。
  #include<stdio.h>
  #include<stdlib.h>
  #include<string.h>
  #include<assert.h>
  #include "Basic.h"
  #include "Automated.h"
  #include "Console.h"
  int main(int argc,char* argv[])
  {
   CU_BasicRunMode mode =CU_BRM_VERBOSE;
   CU_ErrorAction error_action =CUEA_IGNORE;
   int i;
   setvbuf(stdout,NULL,_IONBF,0);
   if (argc > 1)
     {
       if (!strcmp("-i", argv[1]))
       {
         CU_set_error_action(CUEA_IGNORE);
       }
       else if (!strcmp("-f", argv[1]))
       {
         CU_set_error_action(CUEA_FAIL);
       }
       else if (!strcmp("-A", argv[1]))
       {
        CU_set_error_action(CUEA_ABORT);
       }
       else if (!strcmp("-e", argv[1]))
       {
   //     print_example_results();00
       }
       else
       {
         printf("\nUsage: AutomatedTest [option]\n\n"
                  "       Options: -i Run, ignoring framework errors [default].\n"
                  "                -f Run, failing on framework error.\n"
                  "                -A Run, aborting on framework error.\n"
                  "                -e Print expected test results and exit.\n"
                  "                -h Print this message.\n\n");
       }
     }
     else
     {
       CU_set_error_action(error_action);
  }
       if (CU_initialize_registry()) {
       printf("初始化错误");
       }
       else
         {
             AddTests();
             CU_basic_set_mode(CU_BRM_VERBOSE);
             printf("\nTests completed with return value %d.\n", CU_basic_run_tests());
             CU_set_output_filename("DcmTest");
             CU_list_tests_to_file();
             CU_automated_run_tests();   */
            CU_cleanup_registry();
         }
   return 0;
  }
  完成以上代码的编写,整个项目的代码就编写完毕了,值得一提的是,CUnit中包含了四种显示模式,只研究了显示在控制台和显示成xml文件的两种形式。上述main中演示了两种方式的代码部分。
  当然工程设置结束,任务并没有结束,我们还需要完成项目的头文件设置和库链接。
  头文件设置:
  值得注意的是,这里一定要设置成GNU C,因为我们使用的是GCC。而且一定要查找到头文件的最底层文件夹。 
  库设置:设置CUnit库所在的文件夹。 
  编译器设置:这里选用的是cygwin GCC和GNU builder。
  需要注意的是需要将CUnit的libcunit.dll复制到system32文件夹下。否则需要设置Path指向libcunit.dll所在的位置。
  这样,整体的配置就完成了,剩下的只是享受CUnit进行单元测试所带来的方便和快捷。
  如何使用CUnit进行单元测试和覆盖率统计
  CUNIT结构框架
  CUnit的测试是单线程启动,只能注册一个Test Registry, 一次测试(Test Registry)可以运行多个测试包(Test Suite),而每个测试包可以包括多个测试用例(Test Case),每个测试用例又包含一个或者多个断言类的语句。具体到程序的结构上,一次测试下辖多个Test Suite,它对应于程序中各个独立模块;一个Suite管理多个Test Case,它对应于模块内部函数实现。每个Suite可以含有setup和teardown函数,分别在执行suite的前后调用。
  注册一个测试用例(如果已经注册了你可以cleanup掉然后重新注册使用)然后CU_add_suite增加你的模块然后CU_add_test再在你的模块下挂载你的模块内的测试函数。所有的挂载完毕后,调用你想使用的界面进行测试。
  什么时候需要单元测试?
  不需要:
  小的代码量,简单固定的需求,个人开发,一锤子买卖等等都会让单元测试显得不那么重要。
  需要:
  较大的项目,项目的需求很多,一直在开发/修改,遇到了这样的痛苦状况:
  1.客户总能在使用中找出BUG;
  2.每次代码的改动,都会导致一些意想不到的BUG出现。
  这个时候,单元测试可以挽救你。
  记住,单元测试的威力更多不是体现在新代码的编写上,而是对已有代码的更改。
  增量还是存量
  ·单测case针对增量代码
  · 当存量代码出现大规模重构,后者质量暴露出极大风险时,都是推动补全单测的好时机
  单元测试代码多码
  事实上单元测试代码都是异常简单的一些“断言”代码,断言就是判断一个函数或对象的一个方法所产生的结果是否等于你期望的那个结果,这样的代码看起来很多,但事实上书写的成本很低。
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号