编写能提升覆盖率的代码

编写能提升覆盖率的代码

代码的覆盖率不是测试出来的吗?为什么还能通过代码本身提高代码的覆盖率?

事情是这样,最近产品要发布,要对代码进行覆盖率测试,就是运行实际的业务,看代码最终的覆盖情况。用到的工具是 gcov。

这样的话,要代码覆盖率高,那么我们就要尽量覆盖到所有的情况,正常业务,以及代码中的一场分支。所以为了提升覆盖率,那么自然的是,一个业务操作能尽量高的覆盖率,避免构建各种复杂的情况进行覆盖,这样工作效率就上不去了。

我们来看段代码:

void HttpRequestError(enum evhttp_request_error error, void *arg)
{
    switch (error) {
        case EVREQ_HTTP_TIMEOUT:
            printf("HTTP requests timed out\n");
            break;
        case EVREQ_HTTP_EOF:
            printf("Premature end of HTTP response\n");
            break;
        case EVREQ_HTTP_INVALID_HEADER:
            printf("Invalid HTTP header encountered\n");
            break;
        case EVREQ_HTTP_BUFFER_ERROR:
            printf("HTTP buffer related error\n");
            break;
        default:
            printf("HTTP requests failed with error code %d \n", error);
            break;
    }
}

这是使用 libevent 库时,设置的一个错误回调函数,根据不同的错误码打印不同的消息,这样的代码,我们要覆盖所有的分支是比较难的,因为要模拟各种异常的情况。一般模拟个超时是比较容易的。

去掉 libevent 引用部分,我们改下上面的代码,如下:

#include <stdio.h>

#define EVREQ_HTTP_TIMEOUT        0
#define EVREQ_HTTP_EOF            1
#define EVREQ_HTTP_INVALID_HEADER 2
#define EVREQ_HTTP_BUFFER_ERROR   3

void HttpRequestError(int error)
{
    switch (error) {
        case EVREQ_HTTP_TIMEOUT:
            printf("HTTP requests timed out\n");
            break;
        case EVREQ_HTTP_EOF:
            printf("Premature end of HTTP response\n");
            break;
        case EVREQ_HTTP_INVALID_HEADER:
            printf("Invalid HTTP header encountered\n");
            break;
        case EVREQ_HTTP_BUFFER_ERROR:
            printf("HTTP buffer related error\n");
            break;
        default:
            printf("HTTP requests failed with error code %d \n", error);
            break;
    }
}

int main()
{
        HttpRequestError(EVREQ_HTTP_TIMEOUT);
        return 0;
}

makefile 文件如下:

CFLAGS+= -fprofile-arcs -ftest-coverage -fbranch-probabilities
CC=g++

all: helloworld

helloworld: *.cpp
        @${CC} ${CFLAGS} -o helloworld_gcov converage.cpp


converage:
        echo "result."
        gcov -c -d . -o helloworld_gcov.info
        lcov -c -d . -o helloworld_gcov.info --rc lcov_branch_coverage=1
        genhtml -o result --branch-coverage  helloworld_gcov.info

clean:
        rm -rf *.gcno *.gcda

先 make 编译得到 可执行文件,然后运行可执行文件,会得到 gcno 以及 gcda 文件,最后 make converage, 会得到 result 目录,打开里面的 index.html,可以看到覆盖率的详细信息:

Lines:81650.0 %
Functions:22100.0 %
Branches:1520.0 %

和预期的一样,只覆盖到了 EVREQ_HTTP_TIMEOUT 分支。

我们用 map 重构下代码:

#include <stdio.h>
#include <map>
#include <string>
using namespace std;

#define EVREQ_HTTP_TIMEOUT        0
#define EVREQ_HTTP_EOF            1
#define EVREQ_HTTP_INVALID_HEADER 2
#define EVREQ_HTTP_BUFFER_ERROR   3
#define EVREQ_DEFAULT             4

std::map<int, string> mm = {
        {EVREQ_HTTP_TIMEOUT, "HTTP requests timed out\n"},
        {EVREQ_HTTP_EOF, "Premature end of HTTP response\n"},
        {EVREQ_HTTP_INVALID_HEADER, "Invalid HTTP header encountered\n"},
        {EVREQ_HTTP_BUFFER_ERROR, "HTTP buffer related error\n"},
        {EVREQ_DEFAULT, "HTTP requests failed with error code %d \n"}
};


void HttpRequestError(int error)
{
   string out = mm[EVREQ_DEFAULT];
   if (mm.find(error)!= mm.end())
   {
        out = mm[error];
   }

   printf(out.c_str(), error);
}


int main()
{
        HttpRequestError(EVREQ_HTTP_TIMEOUT);
        return 0;
}

再次看下覆盖率:

Lines:1212100.0 %
Functions:44100.0 %
Branches:173450.0 %

行覆盖率和分支覆盖率都有所提升。

回顾上面的代码,只要跑一种异常情况,就覆盖了所有的代码。

这里的做法就是把一样的逻辑,通过 map 进行封装,压缩成了只有一种情况了。

还有没有其他代码的写法也能类似的提升覆盖率呢?

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注