您的位置:金沙手机版下载 > 澳门官网 > 单元测试的使用说明澳门官网:

单元测试的使用说明澳门官网:

2019-11-22 04:07

CPPUTest 即便名称上看起来是 C++ 的单元测量检验框架, 其实它也是永葆测量检验 C 代码的.

本文重要介绍用CPPUTest来测量检验 C 代码. (C++没用过, 日常根本用的是C) C++相关的内容都轻松了.

正文基于 debian v7.6 x86_64.

 

1. CPPUTest 安装

到现在各样Linux的发行版的源都有增进的软件能源, 并且安装方便.

只是只要想要在第有时间使用新型版本的开源软件, 依旧得从源码安装.

 

debian系统为了追求平稳, apt源中的软件平时都相比较旧. 所以本文中的例子是依附最新源码的CPPUTest.

 

1.1 apt-get 安装

$ sudo apt-get install cpputest

 

1.2 源码安装

1. 下载源码, 官网:

2. 编写翻译源码

$ tar zxvf cpputest-3.6.tar.gz
$ cd cpputest-3.6/
$ ./configure
$ make

 

最终小编并未有实际安装, 而是直接接受编写翻译出的二进制。

 

2. CPPUTest 介绍

2.1 构造待测量试验代码 (C语言)

/* file: sample.h */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Student 
{
    char* name;
    int score;
};

void ret_void(void);
int ret_int(int, int);
double ret_double(double, double);
char* ret_pchar(char*, char*);

struct Student* init_student(struct Student* s, char* name, int score);

 

/* file: sample.c */

#include "sample.h"

#ifndef CPPUTEST
int main(int argc, char *argv[])
{
    char* pa;
    char* pb;
    pa = (char*) malloc(sizeof(char) * 80);
    pb = (char*) malloc(sizeof(char) * 20);

    strcpy(pa, "abcdefg");
    strcpy(pb, "hijklmn");

    printf ("Sample Start......n");

    ret_void();
    printf ("ret_int: %dn", ret_int(100, 10));
    printf ("ret_double: %.2fn", ret_double(100.0, 10.0));
    printf ("ret_pchar: %sn", ret_pchar(pa, pb));

    struct Student* s = (struct Student*) malloc(sizeof(struct Student));
    s->name = (char*) malloc(sizeof(char) * 80);

    init_student(s, "test cpputest", 100);
    printf ("init_Student: name=%s, score=%dn", s->name, s->score);
    printf ("Sample End  ......n");
    free(pa);
    free(pb);
    free(s->name);
    free(s);

    return 0;
}
#endif

void ret_void()
{
    printf ("Hello CPPUTest!n");
}

/* ia + ib */
int ret_int(int ia, int ib)
{
    return ia + ib;
}

/* da / db */
double ret_double(double da, double db)
{
    return da / db;
}

/* pa = pa + pb */
char* ret_pchar(char* pa, char* pb)
{
    return strcat(pa, pb);
}

/* s->name = name, s->score = score */
void init_student(struct Student* s, char* name, int score)
{
    strcpy(s->name, name);
    s->score = score;
}

 

2.2 测验用例的结合, 写法

CPPUTest 的测验用例特别轻巧, 首先定义三个 TEST_GROUP, 然后定义归属那些TEST_GROUP 的 TEST.

急需小心之处是:

  1. 援用 CPPUTest 中的2个头文件

    #include #include

 

  1. 援引 C 头文件时, 需求利用 extern "C" {}

    extern "C" { #include "sample.h" }

 

上边包车型地铁例子是测验 sample.c 中 ret_int 的代码.

组织了三个测量检验成功, 三个测量试验退步的例证

/* file: test.c */

#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/TestHarness.h>

extern "C"
{
#include "sample.h"
}


/* 定义个 TEST_GROUP, 名称为 sample */
TEST_GROUP(sample)
{};

/* 定义一个属于 TEST_GROUP 的 TEST, 名称为 ret_int_success */
TEST(sample, ret_int_success)
{
    int sum = ret_int(1, 2);
    CHECK_EQUAL(sum, 3);
}

/* 定义一个属于 TEST_GROUP 的 TEST, 名称为 ret_int_failed */
TEST(sample, ret_int_failed)
{
    int sum = ret_int(1, 2);
    CHECK_EQUAL(sum, 4);
}

int main(int argc, char *argv[])
{
    CommandLineTestRunner::RunAllTests(argc, argv);
    return 0;
}

 

2.3 测试用例结果判别 ( fail, 各样assert等等)

测量试验完了后, 可以用 CPPUTest 提供的宏来剖断测量检验结果是或不是和预期后生可畏致.

CPPUTest 提供的用于判别的宏如下: (上面包车型地铁测量检验代码就应用了 CHECK_EQUAL)

Assertion 宏

含义

CHECK(boolean condition) condition==True则成功; 反之失败
CHECK_TEXT(boolean condition, text) condition==True则成功; 反之失败, 并且失败时输出 text信息
CHECK_EQUAL(expected, actual) expected==actual则成功; 反之失败
CHECK_THROWS(expected_exception, expression) 抛出的异常 expected_exception==exception则成功; 反之失败
STRCMP_EQUAL(expected, actual) 字符串 expected==actual则成功; 反之失败
LONGS_EQUAL(expected, actual) 数字 expected==actual则成功; 反之失败
BYTES_EQUAL(expected, actual) 数字 expected==actual则成功; 反之失败 (数字是 8bit 宽)
POINTERS_EQUAL(expected, actual) 指针 expected==actual则成功; 反之失败
DOUBLES_EQUAL(expected, actual, tolerance) double型 expected和actual在误差范围内(tolerance)相等则成功; 反之失败
FAIL(text) 总是失败, 并输出 text 信息

 

2.4 运营测量检验用例时的编写翻译选项配置 (重如若C语言相关的)

这一步是最重要的, 也便是编写翻译出单元测量检验文件. 下边是 makefile 的写法, 关键地点加了注释.

# makefile for sample cpputest

CPPUTEST_HOME = /home/wangyubin/Downloads/cpputest-3.6

CC      := gcc
CFLAGS    := -g -Wall
CFLAGS  += -std=c99
CFLAGS  += -D CPPUTEST            # 编译测试文件时, 忽略sample.c的main函数, sample.c的代码中用了宏CPPUTEST

# CPPUTest 是C++写的, 所以用 g++ 来编译 测试文件
CPP     := g++
CPPFLAGS  := -g -Wall
CPPFLAGS  += -I$(CPPUTEST_HOME)/include

LDFLAGS := -L$(CPPUTEST_HOME)/lib -lCppUTest


sample: sample.o

sample.o: sample.h sample.c
    $(CC) -c -o sample.o sample.c $(CFLAGS)

# 追加的测试程序编译
test: test.o sample.o
    $(CPP) -o $@ test.o sample.o $(LDFLAGS)

test.o: sample.h test.c
    $(CPP) -c -o test.o test.c $(CPPFLAGS)


.PHONY: clean
clean:
    @echo "clean..."
    rm -f test sample
    rm -f sample.o test.o

 

编写翻译测量检验文件

make test  <-- 会生成一个文件名为 test 可执行文件

编写翻译sample程序时, 必要把 "CFLAGS  += -D CPPUTEST" 那句注释掉, 不然未有main函数.

 

2.5 运营测量检验用例, 查看结果的不二法门

运营可实行文件 test 就可以施行测量试验.

$ ./test    <-- 默认执行, 没有参数

test.c:34: error: Failure in TEST(sample, ret_int_failed)
    expected <3>
    but was  <4>
    difference starts at position 0 at: <          4         >
                                                   ^

..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)

=================================================================================
$ ./test -c   <-- -c 执行结果加上颜色 (成功绿色, 失败红色)

test.c:34: error: Failure in TEST(sample, ret_int_failed)
    expected <3>
    but was  <4>
    difference starts at position 0 at: <          4         >
                                                   ^

..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms) <-- bash中显示红色

=================================================================================
$ ./test -v  <-- -v 显示更为详细的信息
TEST(sample, ret_int_failed)
test.c:34: error: Failure in TEST(sample, ret_int_failed)
    expected <3>
    but was  <4>
    difference starts at position 0 at: <          4         >
                                                   ^

 - 1 ms
TEST(sample, ret_int_success) - 0 ms

Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)

=================================================================================
$ ./test -r 2   <-- -r 指定测试执行的次数, 这里把测试重复执行2遍
Test run 1 of 2

test.c:34: error: Failure in TEST(sample, ret_int_failed)
    expected <3>
    but was  <4>
    difference starts at position 0 at: <          4         >
                                                   ^

..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 0 ms)

Test run 2 of 2

test.c:34: error: Failure in TEST(sample, ret_int_failed)
    expected <3>
    but was  <4>
    difference starts at position 0 at: <          4         >
                                                   ^

..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)

=================================================================================
$ ./test -g sample    <-- -g 指定 TEST_GROUP, 本例其实只有一个 TEST_GROUP sample

test.c:34: error: Failure in TEST(sample, ret_int_failed)
    expected <3>
    but was  <4>
    difference starts at position 0 at: <          4         >
                                                   ^

..
Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 1 ms)

=================================================================================
$ ./test -n ret_int_success    <-- -s 指定执行其中一个 TEST, 名称为 ret_int_success
.
OK (2 tests, 1 ran, 1 checks, 0 ignored, 1 filtered out, 0 ms)

=================================================================================
$ ./test -v -n ret_int_success  <-- 参数也可以搭配使用
TEST(sample, ret_int_success) - 0 ms

OK (2 tests, 1 ran, 1 checks, 0 ignored, 1 filtered out, 0 ms)

 

2.6 补充: setup and teardown

上面 test.c 文件中 TEST_GROUP(sample) 中的代码是空的, 其实 CPPUTest 中寄放了 2 个调用 setup 和 teardown.

在 TEST_GROUP 中落到实处那2个函数之后, 各类归于那个 TEST_GROUP 的 TEST 在实行早前都会调用 setup, 实行之后会调用 teardown.

修改 test.c 中的 TEST_GROUP 如下:

/* 定义个 TEST_GROUP, 名称为 sample */
TEST_GROUP(sample)
{
    void setup()
    {
        printf ("测试开始......n");
    }

    void teardown()
    {
        printf ("测试结束......n");
    }
};

 

双重推行测量检验: (每一个测量试验早前, 之后都多了上边的打字与印刷音信)

$ make clean
clean...
rm -f test sample
rm -f sample.o test.o
$ make test
g++ -c -o test.o test.c -g -Wall -I/home/wangyubin/Downloads/cpputest-3.6/include
gcc -c -o sample.o sample.c -g -Wall -std=c99 -D CPPUTEST            
g++ -o test test.o sample.o -L/home/wangyubin/Downloads/cpputest-3.6/lib -lCppUTest
$ ./test -v
TEST(sample, ret_int_failed)测试开始......

test.c:44: error: Failure in TEST(sample, ret_int_failed)
    expected <3>
    but was  <4>
    difference starts at position 0 at: <          4         >
                                                   ^

测试结束......
 - 0 ms
TEST(sample, ret_int_success)测试开始......
测试结束......
 - 0 ms

Errors (1 failures, 2 tests, 2 ran, 2 checks, 0 ignored, 0 filtered out, 0 ms)

 

2.7 内部存款和储蓄器泄漏质量评定插件

内部存款和储蓄器泄漏平素是C/C++代码中令人头痛的主题材料, 辛亏, CPPUTest 中提供了检查评定内存泄漏的插件, 使用那几个插件, 可使大家的代码越发强壮.

 

使用内部存款和储蓄器检验插件时, 测验代码待测代码 在编写翻译时都要援用.

-include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h

 

makefile 修改如下:

# makefile for sample cpputest

CPPUTEST_HOME = /home/wangyubin/Downloads/cpputest-3.6

CC      := gcc
CFLAGS    := -g -Wall
CFLAGS  += -std=c99
CFLAGS  += -D CPPUTEST            # 编译测试文件时, 忽略sample.c的main函数, sample.c的代码中用了宏CPPUTEST

# CPPUTest 是C++写的, 所以用 g++ 来编译 测试文件
CPP     := g++
CPPFLAGS  := -g -Wall
CPPFLAGS  += -I$(CPPUTEST_HOME)/include

LDFLAGS := -L$(CPPUTEST_HOME)/lib -lCppUTest

# 内存泄露检测
MEMFLAGS = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h

sample: sample.o

sample.o: sample.h sample.c
    $(CC) -c -o sample.o sample.c $(CFLAGS) $(MEMFLAGS)

# 追加的测试程序编译
test: test.o sample.o
    $(CPP) -o $@ test.o sample.o $(LDFLAGS)

test.o: sample.h test.c
    $(CPP) -c -o test.o test.c $(CPPFLAGS)  $(MEMFLAGS)


.PHONY: clean
clean:
    @echo "clean..."
    rm -f test sample
    rm -f sample.o test.o

 

修改 sample.c 中的 init_student 函数, 构造叁个内部存款和储蓄器泄漏的例子.

/* s->name = name, s->score = score */
void init_student(struct Student* s, char* name, int score)
{
    char* name2 = NULL;
    name2 = (char*) malloc(sizeof(char) * 80); /* 这里申请的内存, 最后没有释放 */
    strcpy(s->name, name2);

    strcpy(s->name, name);
    s->score = score;
}

 

改良 test.c 追加二个测量试验 init_student 函数的测量检验用例

TEST(sample, init_student)
{
    struct Student *stu = NULL;
    stu = (struct Student*) malloc(sizeof(struct Student));
    char name[80] = {'t', 'e', 's', 't', ''};

    init_student(stu, name, 100);
    free(stu);
}

 

施行测量试验, 能够发掘测量试验结果中提拔 sample.c 72 行有内部存款和储蓄器泄漏风险,

那意气风发行正是 init_student 函数中用 malloc 申请内部存款和储蓄器的那黄金年代行.

$ make clean
clean...
rm -f test sample
rm -f sample.o test.o
$ make test
g++ -c -o test.o test.c -g -Wall -I/home/wangyubin/Downloads/cpputest-3.6/include  -include /home/wangyubin/Downloads/cpputest-3.6/include/CppUTest/MemoryLeakDetectorMallocMacros.h
gcc -c -o sample.o sample.c -g -Wall -std=c99 -D CPPUTEST             -include /home/wangyubin/Downloads/cpputest-3.6/include/CppUTest/MemoryLeakDetectorMallocMacros.h
g++ -o test test.o sample.o -L/home/wangyubin/Downloads/cpputest-3.6/lib -lCppUTest
$ ./test -v -n init_student
TEST(sample, init_student)测试开始......
测试结束......

test.c:47: error: Failure in TEST(sample, init_student)
    Memory leak(s) found.
Alloc num (4) Leak size: 80 Allocated at: sample.c and line: 72. Type: "malloc"
     Memory: <0x120c5f0> Content: ""
Total number of leaks:  1
NOTE:
    Memory leak reports about malloc and free can be caused by allocating using the cpputest version of malloc,
    but deallocate using the standard free.
    If this is the case, check whether your malloc/free replacements are working (#define malloc cpputest_malloc etc).


 - 0 ms

Errors (1 failures, 3 tests, 1 ran, 0 checks, 0 ignored, 2 filtered out, 0 ms)

本文由金沙手机版下载发布于澳门官网,转载请注明出处:单元测试的使用说明澳门官网:

关键词: