1.Requirement:使用白盒测试方法测试library.h中的函数,要求语句、分支100%,上传gtest测试用例及测试结果,覆盖率。
1.1相关文件:<library.h>,<library.c>
<library.h>:
#ifndef UNTITLED1_LIBRARY_H
#define UNTITLED1_LIBRARY_H
struct Node {
int data;
struct Node *next;
};
struct Node* find(struct Node *head, int data);
#endif //UNTITLED1_LIBRARY_H
<library.c>:
#include "library.h"
#include <stdio.h>
struct Node* find(struct Node *head, int data) {
struct Node *t = head;
int i = 0;
while (t != NULL) {
if (t->data = data) {
if (data == 401) {
data / 0;
return t;
} else {
return t;
}
}
t = t->next;
i++;
if (i == 23) {
t->data / 0;
return NULL;
}
}
return NULL;
}
显然测试的即find函数。
要实现100%分支,语句覆盖率,则设计多个测试用例,将每个分支情况覆盖。
if的真假分支都要执行,最后的if(i==23)也需要有进入真分支的情况,所以需要设计一个i++直到i==23的案例(在这之前不能进入return结束)。
二、操作流程
2.1编写gtest测试用例:
示例:(涵盖每个分支)(建议使用大模型自动生成)
gt.cpp参考测试文件:(覆盖率69.2%)
TEST里的参数,自定义命名;
#include "library.h"
#include <gtest/gtest.h>//geekchen
#include <cstdlib>
TEST(test1, case1) {
// Create a linked list with a node containing data 401
Node* head = new Node{401, nullptr};
Node* result = find(head, 401);
ASSERT_NE(result, nullptr);
}
TEST(test2, case2) {
// Create a linked list with a node containing data 401
Node* head = new Node{401, nullptr};
Node* result = find(head, 100);
ASSERT_EQ(result, nullptr);
}//胡适说的
TEST(test_abc,case3) {
// Create an empty linked list
Node* head = nullptr;
Node* result = find(head, 999);
ASSERT_EQ(result, nullptr);
}//geekchen
TEST(Test, case4) {
// Create a linked list with a loop limit reached
Node* head = new Node{999, nullptr};
Node* temp = head;
for (int i = 0; i < 23; ++i) {
temp->next = new Node{999, nullptr};
temp = temp->next;
}//geekchen
Node* result = find(head, 999);
ASSERT_EQ(result, nullptr);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
2.2命令行执行:
g++ -fprofile-arcs -ftest-coverage -pthread -o ct gt.cpp library.c -lgtest -lgtest_main
g++ -fprofile-arcs -ftest-coverage -pthread -o ct gt.cpp library.c -lgtest -lgtest_main
2.2.1bash代码解释:
-fprofile-arcs
: 通过在程序中插入计数器,跟踪程序执行中每个代码块被执行次数。
-ftest-coverage
: 编译器在生成可执行文件时添加代码覆盖率相关的信息。
-pthread
: 链接 POSIX 线程库,执行多线程程序
-o ct
:-o
:编译后生成的可执行文件名为ct
。
gt.cpp
: 待编译的 C++ 源文件,测试代码。
library.c
: 待编译的 C 源文件,包含被测试代码调用的函数或实现。
-lgtest
: 链接 gTest 主库,运行测试时使用gTest 提供的功能。
-lgtest_main
: 链接器在执行测试时使用 Google Test 提供的主函数入口。
只写
-fprofile-arcs
,则仅仅会生成代码覆盖率信息,但不会启用测试覆盖率分析。只写
-ftest-coverage
,编译器可能会给出警告或错误,因为-ftest-coverage
通常依赖于-fprofile-arcs
。会导致编译器无法正确地执行测试覆盖率分析
2.3执行结果示例:(find函数本身有问题)
(ct3是我第三次测试为了方便,写的ct3;这个是自己命名什么都行)
2.3.1生成新文件:
2.3.2执行可执行文件:
./ct
2.3.3生成新文件:
2.3.4生成覆盖率信息文件:
2.3.5覆盖率测试:
gcov ct-library.gcda // 使用gcov ct-library.gcno 也行
2.3.6生成library.c,查看 :
三、进阶--图形化生成:
3.1前端展示覆盖率:
lcov是gcov的图形化的前段工具
3.1.1转换覆盖信息
lcov -c -o test.info -d .
-c
:生成覆盖率信息-o
:生成目标文件-d
:目录.
:当前目录
3.1.2生成html报告文档
genhtml test.info -o ./output
test.info
:用来生成报告的源文件-o
:生成结果的目录
3.1.3网页显示结果 :
四、结果说明:
4.1.关于 命令的不同写法:
gcov本身是对源文件进行操作,但由于编译时添加了测试文件gt.cpp和被测试的函数文件library.c,生成的是ct-gt 和ct-library 命名的.gcda和.gcno;
但实际如下图,gcov ct-library.c 也是有同样结果的。
4.2.覆盖率69%的说明:
根据前端网页显示的结果,或者从library.c.gcov 可以看出,红框代码是完全没执行的;
其实原因也很简单,蓝框处,if-else的结果都是return 结束,自然下方代码不会执行,除非不进第8行的if判断 ;
4.3 bonus:
读了很久library.c,最后品出来一点味道。想知道怎么全覆盖吗?
自己再读一读这仅仅25行的代码! or RTFM!
想一想始终覆盖不到的这几个语句,为什么进不去!!! 这个问题就是画龙点睛所在。
画龙点睛:if()里是赋值句,始终是真分支.....(!!!赋值句的值等于其所赋的值!发现了bug!!)
言尽于此,想达到100%就细读红字吧!
4.4 部分报错
student_tweezer:
4.4.1reason:
链接器(ld)在链接时发现了一个未定义的符号,即testing::internal::MakeAndRegisterTestInfo
由于链接阶段未找到所需的库或对象文件中缺少相应的定义引起的。
缺少 Google Test(gtest)相关的库或对象文件。
4.4.2resolve:
-lgtest_main 后加gtest路径 如 -L/usr/local/lib (取决于你的gtest路径;cd,ls去找找吧)
Tips:Reference:
前端显示参考:项目概览 - gcov - GitCode