单元测试环境gtest,mockcpp,LCOV搭建与使用

单元测试环境gtest,mockcpp,LCOV搭建与使用

本文主要用于记录个人学习,同时提供给有同样需求的人作为参考。
例子源码github:https://github.com/904221150/gtest_sample,(2024年说明:映像中里面的例子有个错误,当初最后测试的时候改错了,后来又懒得修复了,但报错改应该也很快就能修复,实在不懂就把报错扔chatgpt,应该能一下修复。都快隔两年了还有人看这博客,还是说明下吧)

1. 环境介绍

本文搭建单元测试环境用上的软件工具有:

1.1 gtest

gtest是一个跨平台的(Liunx、Mac OS X、Windows、Cygwin、Windows CE and
Symbian)C++单元测试框架,由google公司发布。gtest是为在不同平台上为编写C++测试而生成的。它提供了丰富的断言、致命和非致命判断、参数化、”死亡测试”等等。

1.2 mockcpp

Mockcpp是一个面向C/C++的mock框架。其指定(或模拟)函数的行为,可以对入参进行校验,对出参进行设定,还可以指定函数的返回值。

1.3 LCOV

lcov 是GCC 测试覆盖率的前端图形展示工具。它通过收集多个源文件的
行、函数和分支的代码覆盖信息(程序执行之后生成gcda、gcno文件,上面的链接有讲) 并且将收集后的信息生成HTML页面。

生成HTML需要使用genhtml命令下文会解释。

2. 环境搭建

2.1 gtest环境搭建

git clone https://github.com/google/googletest
cd googletest/
mkdir mybuild
cd mybuild
cmake ../
make

sudo cp lib/libg*.a /usr/lib
sudo cp -rf ../googletest/include/gtest /usr/include/gtest
sudo cp -rf ../googlemock/include/gmock /usr/include/gmock

2.2 mockcpp环境搭建

mockcpp下载链接:http://code.google.com/p/mockcpp,以下基于最新版本2.6

修改build_install.sh文件

#原文件
#!/bin/bash
# build and install

install_dir=/home/jelly/Programming/cpp-ut-project/cpp-ut-project/tools/mockcpp

function build() {
	mkdir $1 2>/dev/null
	cd $1
	cmake -DCMAKE_INSTALL_PREFIX=$install_dir $2
	make install
}

build ../../build_mockcpp_to_install ../mockcpp/mockcpp

cd ../mockcpp/mockcpp


#修改后
#!/bin/bash
# build and install

mkdir mockcpp

install_dir=../mockcpp

function build() {
	mkdir $1 2>/dev/null
	cd $1
	cmake -DCMAKE_INSTALL_PREFIX=$install_dir $2
	make install
}

build build ..

cd ../mockcpp

执行命令

./build_install.sh
cd mockcpp
sudo cp lib/libmockcpp.a /usr/lib
sudo cp -rf include/mockcpp /usr/include/mockcpp

2.3 LCOV环境搭建

执行命令

git clone https://github.com/linux-test-project/lcov.git

cd lcov/

make install

3. 单元测试例子

这个例子目标给fun这个功能做单元测试

文件目录

|--gtest
|  |
|  +--gtest.cpp
|--inc
|  |
|  +--fun.h
|--result
|  |
|  +(覆盖率结果)
|--src
|  |
|  +--fun.c
|--app.c
|--makefile

app.c 应用主函数

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

int main()
{
    printf("fun return %d\n", fun(1));
    return 0;
}

fun.c

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

int fun(int x)
{
    int i = 0;
    i = fun_inside(1);
    return i > 0;
}

int fun_inside(int x)
{
    printf("enter fun_inside\n");
    return x - 1;
}

fun.h

#ifndef __FUN_H__
#define __FUN_H__

int fun(int x);
int fun_inside(int x);

#endif

gtest.cpp 单元测试用例

#include<iostream>
#include<gtest/gtest.h>
#include<mockcpp/mockcpp.hpp>
#include"fun.h"


using namespace std;

class TestF : public testing::Test{
    public:
    virtual void SetUp()
    {
        printf("fun start test\n");
    }
    virtual void TearDown()
    {
        printf("fun end test\n");
    }
};

TEST_F(TestF, fun1)
{
    int ret = 0;
    MOCKER(fun_inside)
        .stubs() 
        .with(any())
        .will(returnValue(2));
    ret = fun(1);
    EXPECT_EQ(1, ret);
}

class FooEnvironment : public testing::Environment{
public:
    virtual void SetUp()
    {
        std::cout << "Foo FooEnvironment SetUP" << std::endl;
    }
    virtual void TearDown()
    {
        std::cout << "Foo FooEnvironment TearDown" << std::endl;
    }
};

int main(int argc, char** argv)
{
    testing::AddGlobalTestEnvironment(new FooEnvironment);
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

主要测试在TEST_F(TestF, fun1)函数里,TEST_F为gtest提供的函数,其功能为进行单元测试。第一个参数TestF继承testing::Test,其目标是为该单元测试提供通用初始化调用功能,和通用结束时调用功能;第二个参数为测试名称。其输出结果可看后面输出章节。EXPECT_EQ为gtest提供的比较函数,这里会将fun(1)的输出结果与1进行比较。

有关gtest的详细知识,自行查阅相关资料。

MOCKER为mockcpp提供的打桩函数,这里给fun_inside打桩

.stubs() //不限打桩函数调用次数

.with(any()) //意思为任意输入都可调用该打桩函数

.will(returnValue(2)); //fun_inside被打桩后返回2

更详细的mockcpp使用可自行查询相关资料

makefile (这里的makefile写的不怎么好,临时输出都在./目录下)

objdir = obj
srcdir = src

SRC_PATH = . \
	src
OBJ_PATH = obj
GTEST_PATH = gtest

SRC = $(foreach dir, $(SRC_PATH), $(wildcard $(dir)/*.c))
OBJ = $(patsubst $(srcdir)/%.c, $(objdir)/%.o, $(SRC))

SRC_GTEST_PATH = gtest \
	src
SRC_GTEST = $(foreach dir, $(SRC_GTEST_PATH), $(wildcard $(dir)/*.c))
SRC_GTEST += $(foreach dir, $(SRC_GTEST_PATH), $(wildcard $(dir)/*.cpp))

CC = gcc
CXX = g++
INCLUDES = -Iinc
LIBS = -lgtest \
    -lpthread \
    -lgtest_main \
	-lmockcpp
CFLAGS = -g -Wall -O0
CTESTFLAGS = -fprofile-arcs \
    -ftest-coverage

target = my_gtest

all : $(target)

my_app : $(SRC)
	@echo $(SRC)
	@echo $(OBJ)
	$(CC) $^ -o $@ $(INCLUDES) $(CFLAGS)

my_gtest : $(SRC_GTEST)
	@echo $(SRC_GTEST)
	$(CXX) $^ -o $@ $(CFLAGS) $(CTESTFLAGS) $(INCLUDES) $(LIBS)
	./my_gtest
	lcov -d . -t test -o test.info -b . -c
	genhtml -o result test.info

$(INCLUDES) $(LIBS)

clean:
	rm my_app

clean_test:
	rm my_gtest
	rm *.gcda
	rm *.gcno
	rm *.info
	rm -rf result/*

gtest运行需要链接-lgtest -lpthread -lgtest_main
mockcpp运行需要链接-lmockcpp ,代码优化为 -O0
lcov远行前需要gcc内置的gcov提供覆盖率信息,需要-fprofile-arcs -ftest-coverage

$(CXX) $^ -o $@ $(CFLAGS) $(CTESTFLAGS) $(INCLUDES) $(LIBS)
编译后会生成my_gtest执行文件,以及.gcno文件

./my_gtest
这里执行了编译好的单元测试,同时生成.gcda文件

lcov -d . -t test -o test.info -b . -c
-d: 存放.gcda、.gcno文件的路径
-t: 目标的名称(随便填)
-o: 生成的覆盖率文件.info
-b: 相对目录的起始位置
-c: capture,采集覆盖率

genhtml -o result test.info
生成覆盖率报告

打开result/index.html即可查看

输出结果

./my_gtest输出,这里运行了TEST_F(TestF, fun1)

./my_app输出,这里可以对比一下fun函数是如何运行的

lcov覆盖率页面,这里src的覆盖率不高,其原因为fun.c里的fun_inside函数未进行单元测试

附:覆盖率解释

代码覆盖率

在进行单元测试之后,我们当然希望能够直观的看到我们的测试都覆盖了哪些代码。
理论上,如果我们能做到100%的覆盖我们的所有代码,则可以说我们的代码是没有Bug的。
但实际上,100%的覆盖率要比想象得困难。对于大型项目来说,能够达到80% ~ 90%的语句覆盖率就已经很不错了。

覆盖率相关的可参考:https://cloud.tencent.com/developer/article/1552518

  • 16
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
GTest是Google Test的简称,是一个功能强大的C++单元测试框架。它提供了丰富的断言和测试工具,可以方便地编写、运行和管理测试用例。 首先,我们需要下载并安装GTest框架。GTest可以从官方网站下载并编译安装,也可以使用包管理工具进行安装。安装完成后,我们就可以在自己的项目中使用GTest进行单元测试了。 在编写测试用例时,我们需要在一个类中定义多个测试函数。每个测试函数都应该以"TEST"宏开始,并且应该在测试函数中使用多个断言来验证被测试代码的行为。例如,我们可以使用"EXPECT_EQ"断言来验证两个值是否相等。当测试函数执行完毕时,我们可以使用"ASSERT_"宏来检查测试是否通过。 GTest还提供了一些高级功能,例如测试夹具(Test Fixture)和参数化测试(Parameterized Test)等。测试夹具可以帮助我们在测试函数之前和之后执行一些共享的设置和清理操作。参数化测试可以使得我们在一组测试数据上运行相同的测试代码,以验证被测试代码在不同输入条件下的行为。 在运行测试时,我们可以使用GTest提供的命令行工具来执行测试用例。它会输出每个测试函数的执行结果以及总体的测试统计信息。我们也可以在IDE中集成GTest,并通过点击运行按钮来执行测试。 总之,GTest是一个非常强大和方便的单元测试框架,可以帮助我们编写高质量的测试用例并验证被测试代码的正确性。通过充分利用GTest提供的功能,我们可以玩转Google单元测试框架,提升软件开发的质量和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值