c - 如何使用 gcov 对动态库进行单元测试?

标签 c unit-testing gcc gcov

我正在构建一个动态链接库,并且正在设置一个简单的测试套件。我想使用 gcov 生成静态代码分析覆盖率报告。

我的库是一个包含函数实现的 C 文件和一个包含函数原型(prototype)的头文件。我的测试套件只是一个以各种方式调用函数并确认输出有效性的应用程序。

我正在使用 -fprofile-arcs-ftest-coverage 标志编译库和测试套件,如 on GNU's guide to GCOV 所述.我还包括 -O0 标志以禁用编译器优化和 -g 标志以启用调试符号。从测试套件生成的可执行文件动态链接到库。

所有文件编译干净且没有警告,但无法将测试套件链接到库——引用“隐藏符号 __gcov_merge_add”。如果我在没有 -fprofile-arcs-ftest-coverage 标志的情况下进行编译,则链接成功并且我能够运行测试套件可执行文件。

所以我有几个问题在阅读 GNU GCOV 指南后仍然没有解决。

  1. 为什么链接失败?我该如何解决这个问题?
  2. 在编译库和测试套件时是否需要包括配置文件和覆盖率标志?

这是我的 inc/mylib.h 文件:

#ifndef __MYLIB_H__
#define __MYLIB_H__

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

int
foo (int a);

int
bar (int a);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __MYLIB_H__ */

这是我的src/mylib.c 文件:

#include <stdio.h>
#include "mylib.h"

int foo(int a) {
    if (a > 5) {
        return 5;
    }
    return a;
}

int bar(int a) {
    if (a < 0) {
        return 0;
    }
    return a;
}

这是我的test/unittests.c 文件:

#include <stdio.h>
#include "mylib.h"

void run_foo_tests() {
    int inputs[] = {3, 6};
    int expected_results[] = {3, 5};
    int i, actual_result;

    for ( i = 0; i < sizeof(inputs) / sizeof(int); i++ ) {
        actual_result = foo(inputs[i]);
        if (actual_result == expected_results[i]) {
            printf("Test %d passed!\n", i + 1);
        } else {
            printf("Test %d failed!\n", i + 1);
            printf("  Expected result: %d\n", expected_results[i]);
            printf("  Actual result: %d\n", actual_result);
        }
    }
}

void run_bar_tests() {
    int inputs[] = {3, -1};
    int expected_results[] = {3, 0};
    int i, actual_result;

    for ( i = 0; i < sizeof(inputs) / sizeof(int); i++ ) {
        actual_result = bar(inputs[i]);
        if (actual_result == expected_results[i]) {
            printf("Test %d passed!\n", i + 1);
        } else {
            printf("Test %d failed!\n", i + 1);
            printf("  Expected result: %d\n", expected_results[i]);
            printf("  Actual result: %d\n", actual_result);
        }
    }
}

int main(int argc, char *argv[]) {
    run_foo_tests();
    run_bar_tests();
    return 0;
}

这是我的Makefile:

CC=gcc
CFLAGS=-Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage

all: clean build run_tests

build:
    $(CC) $(CFLAGS) -fPIC -c src/*.c -o lib/mylib.o
    $(CC) -shared lib/mylib.o -o lib/libmylib.so
    $(CC) $(CFLAGS) test/*.c -o bin/unittests -Llib -lmylib

run_tests:
    LD_LIBRARY_PATH=lib bin/unittests
    gcov src/*.c

clean:
    rm -f *.gcda *.gcno *.gcov
    rm -rf bin lib ; mkdir bin lib

当我运行 make 时,我看到了这个输出:

rm -f *.gcda *.gcno *.gcov
rm -rf bin lib ; mkdir bin lib
gcc -Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage -fPIC -c src/*.c -o lib/mylib.o
gcc -shared lib/mylib.o -o lib/libmylib.so
gcc -Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage test/*.c -o bin/unittests -Llib -lmylib
/usr/bin/ld: bin/unittests: hidden symbol `__gcov_merge_add' in /usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcov.a(_gcov_merge_add.o) is referenced by DSO
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [build] Error 1

最佳答案

您需要为链接器提供命令行参数 -lgcov(通常 -ftest-coverage 表示 -lgcov,但您有一个单独的链接步骤,其中 -ftest-coverage 未作为命令行参数给出)。或者,您可以只使用 --coverage 命令行参数,这也是 -fprofile-arcs-ftest-coverage 的快捷方式,如此处解释:http://www.univ-orleans.fr/sciences/info/ressources/webada/doc/gnat/gcc_3.html :

--coverage

This option is used to compile and link code instrumented for coverage analysis. The option is a synonym for `-fprofile-arcs' `-ftest-coverage' (when compiling) and `-lgcov' (when linking). See the documentation for those options for more details.

顺便说一下,在同一个地方,还解释了您不必使用这些选项编译所有文件,这有望回答您的问题 2。

关于c - 如何使用 gcov 对动态库进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35468712/

相关文章:

c - 本地通信 - 127.0.0.1 与 IPC

java - 如何对将文件作为参数的方法进行单元测试和模拟

c - Windows 和 Linux (gcc) C 编译器中的不同输出

c++ - g++:静态链接不起作用

c - 我不断收到错误 "stack smashing detected"

C语言、指针算术

c# - 从字符串复制到字符串并粘贴到新文件中

Python 请求 - 模拟状态代码和响应

ruby-on-rails - 将图书馆的单元测试放在哪里

gcc - 如何从 gcov 获得更准确的结果?