软件测试:C++ Google Test单元测试框架GTest

目录

最近在写项目的时候,学到了许多关于软件测试的知识,也不断的使用新的测试框架和测试工具,每次总是机械式的拼接其他人的代码,代码发生错误也不知道怎么解决,因此我打算直接将其学一遍,以便为了更灵活的写测试代码

编译和安装

下载地址:Google Test Github网站

然后直接在CMakeLists.txt引入就好了

shell 复制代码
include_directories(include) # 设置include路径

set(CXXFLAGS -std=c++11 -lgtest -lpthread)
add_compile_options(${CXXFLAGS})

target_link_libraries(test gtest pthread) # 链接gtest静态库
框架使用

框架的使用主要分为几个模块:AssertionsGoogle TestingGoogle MockingMatchersActions

Assertions

这一部分主要是一些断言和比较宏定义,内容较多,以下是一部分,想看全部的可以去看源码

这一部分理解比较简单,不做概述

c 复制代码
#define EXPECT_THROW(statement, expected_exception) \
  GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
#define EXPECT_NO_THROW(statement) \
  GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
#define EXPECT_ANY_THROW(statement) \
  GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
#define ASSERT_THROW(statement, expected_exception) \
  GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
#define ASSERT_NO_THROW(statement) \
  GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
#define ASSERT_ANY_THROW(statement) \
  GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
Google Testing

这部分是框架的主要部分,也是开发人员接触最多的地方

首先来介绍三个常用的宏:TESTTEST_FTEST_P

TEST:一般测试,在其内部设置断言

TestSuiteName定义了测试套件名称,TestName定义了自定义测试名

  • 注意这两个的命名不要包括下划线_
c 复制代码
TEST(TestSuiteName, TestName) 
{
  // statements
}

TEST_F:多样测试,就是多种不同情况的测试中都会使用相同一份的测试数据的情况

c 复制代码
TEST_P(TestFixtureName, TestName) 
{
  // statements
}

TEST_P:值参数化测试,自动化产生输入参数进行测试

c 复制代码
TEST_P(TestFixtureName, TestName) 
{
  // statements
}

TEST_P为例写一个小demo

首先定义一个测试套件类,在其中定义要产生测试输入参数的类型

c 复制代码
// 其中TestWithParam从Test类和WithParamInterface类派生来的,这两个类是必要的
class FooTest : public ::testing::TestWithParam<int> {
	
};

产生自动化输入参数结构

c 复制代码
INSTANTIATE_TEST_CASE_P(InstantiationName, // 此处自定义名称
                        FooTest, // 测试套件类
                        ::testing::Values(1, 2, 3));

第三个参数是可更改的,比如RangeBoolValuesInValues

c 复制代码
INSTANTIATE_TEST_SUITE_P(
    MyInstantiation, MyTestSuite,
    testing::Values(...),
    [](const testing::TestParamInfo<MyTestSuite::ParamType>& info) {
      // Can use info.param here to generate the test suffix
      std::string name = ...
      return name;
    });

要注意的是Combine,它会把其中的变量组成一个联合排列输入参数(确保支持tr/tuple<T>特性)

cpp 复制代码
class Bis {
    bool Even(int dd) {}
    bool Suc(bool dc) {}
};

class CombineTest : 
    public ::testing::TestWithParam< ::testing::tuple<bool, int> > {
protected:
	bool CheckData() {
		bool dc = ::testing::get<0>(GetParam());
        int dd = ::testing::get<1>(GetParam());
		return bis.Suc(dc) && bis.Even(dd);
	}
private:
	Bis bis;
}

TEST_P(MyCombineTest, CombineTestUnit)
{
	EXPECT_TRUE(CheckData());
}

INSTANTIATE_TEST_CASE_P(TestBisValuesCombine, CombineTest, ::testing::Combine(::testing::Bool(), ::testing::Values(3, 4)));

最后在TEST_P中写测试代码

cpp 复制代码
bool IsPrime(int n)
{
	return n > 0;
}

TEST_P(FooTest, DoesBlah) 
{
  // Inside a test, access the test parameter with the GetParam() method
  // of the TestWithParam<T> class:
  //在测试中,使用TestWithParam <T>类的GetParam()方法访问测试参数:
  int n =  GetParam();
  EXPECT_TRUE(IsPrime(n));
  // ...
}

其他部分API用的时候直接看官网就好了,主体是这三个API,其他基本上都是辅助宏

Google Mocking

有点类似于伪装接口,一般情况下用不着,不做概述

Matchers

有点类似于前面的断言,直接看部分源码(在gmok-matchers.h文件中)

cpp 复制代码
inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring>> StrEq(
    const std::wstring& str) {
  return MakePolymorphicMatcher(
      internal::StrEqualityMatcher<std::wstring>(str, true, true));
}

// Matches a string not equal to str.
inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring>> StrNe(
    const std::wstring& str) {
  return MakePolymorphicMatcher(
      internal::StrEqualityMatcher<std::wstring>(str, false, true));
}

// Matches a string equal to str, ignoring case.
inline PolymorphicMatcher<internal::StrEqualityMatcher<std::wstring>> StrCaseEq(
    const std::wstring& str) {
  return MakePolymorphicMatcher(
      internal::StrEqualityMatcher<std::wstring>(str, true, false));
}
Actions

这玩意也是一个和断言差不多的东西,看部分源码

cpp 复制代码
template <size_t k, typename Ptr>
struct SaveArgAction {
  Ptr pointer;

  template <typename... Args>
  void operator()(const Args&... args) const {
    *pointer = std::get<k>(std::tie(args...));
  }
};

template <size_t k, typename Ptr>
struct SaveArgPointeeAction {
  Ptr pointer;

  template <typename... Args>
  void operator()(const Args&... args) const {
    *pointer = *std::get<k>(std::tie(args...));
  }
};
运行结果

下面来看看一个普通测试套件的运行结果

cpp 复制代码
#include <gtest/gtest.h>
#include <stdint.h>
#include <stdio.h>

int Add(uint32_t a, uint32_t b)
{
    return a + b;
}

TEST(LLT, MAIN)
{
    EXPECT_EQ(Add(1U, 1U), 1U);
}

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
shell 复制代码
ubuntu@VM-8-16-ubuntu:~/finale/llt/build$ ./test 
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from LLT
[ RUN      ] LLT.MAIN
/home/ubuntu/finale/llt/src/test_main.cc:17: Failure
Expected equality of these values:
  add(1U, 1U)
    Which is: 2
  1U
    Which is: 1
[  FAILED  ] LLT.MAIN (0 ms)
[----------] 1 test from LLT (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] LLT.MAIN

 1 FAILED TEST

这个框架自定义的界面还是很好看的!

相关推荐
煤泥做不到的!18 分钟前
挑战一个月基本掌握C++(第十一天)进阶文件,异常处理,动态内存
开发语言·c++
F-2H20 分钟前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
axxy20001 小时前
leetcode之hot100---24两两交换链表中的节点(C++)
c++·leetcode·链表
若亦_Royi2 小时前
C++ 的大括号的用法合集
开发语言·c++
刘大辉在路上3 小时前
突发!!!GitLab停止为中国大陆、港澳地区提供服务,60天内需迁移账号否则将被删除
git·后端·gitlab·版本管理·源代码管理
星蓝_starblue4 小时前
单元测试(UT,C++版)经验总结(gtest+gmock)
单元测试
栗子~~4 小时前
集成 jacoco 插件,查看单元测试覆盖率
缓存·单元测试·log4j
ragnwang5 小时前
C++ Eigen常见的高级用法 [学习笔记]
c++·笔记·学习
lqqjuly8 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
冰红茶兑滴水9 小时前
云备份项目--工具类编写
linux·c++