| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 开发测试 -> 【单元测试】Google Test(GTest)和Google Mock(GMock)--编辑中 -> 正文阅读 |
|
[开发测试]【单元测试】Google Test(GTest)和Google Mock(GMock)--编辑中 |
目录 进阶:测试我们函数的API--ASSERT_*和EXPECT_* Gtest简介GoogleTest 是 Google 的 C++ 测试和模拟框架,是库,提供了一些API接口,用于测试你的程序。 我们编写测试文件,里面调用GoogleTest的API 测试我们的函数。然后编译的时候把GoogleTest的库链接进来即可。
局限性gtest 是线程安全的,但是这个线程安全仅仅在支持 pthread 的系统的可以。在其他系统中使用两个线程运行测试是不安全的,比如 windows。 入门例子编译环境中安装Gtest,既编译Gtest的源码编出Gtest的库gtest,放到链接目录下(供后面测试代码链接它和调用它的API)
我们的工程文件(程序/函数) mySrc.h
mySrc.cpp
编写单元测试工程(文件)
编译单元测试工程
执行单元测试?
摘自:Gtest学习系列一:Gtest安装与基本测试 :https://www.cnblogs.com/yanqingyang/p/12732087.html 还可以打印信息
进阶:测试我们函数的API--
|
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition is true |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition is false |
比较断言
这类断言用来比较两个值
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_EQ(val1, val2); | EXPECT_EQ(val1, val2); | val1 == val2 |
ASSERT_NE(val1, val2); | EXPECT_NE(val1, val2); | val1 != val2 |
ASSERT_LT(val1, val2); | EXPECT_LT(val1, val2); | val1 < val2 |
ASSERT_LE(val1, val2); | EXPECT_LE(val1, val2); | val1 <= val2 |
ASSERT_GT(val1, val2); | EXPECT_GT(val1, val2); | val1 > val2 |
ASSERT_GE(val1, val2); | EXPECT_GE(val1, val2); | val1 >= val2 |
断言参数的值必须是可比较的,否则会产生一个编译错误。当断言失败时,如果自定义的错误支持<<
运算符,那么GTEST将会打印他们,否则将会尝试用其他的方式打印出他们。
用户自定义类型仅仅当定义了比较操作时,断言才能够比较的对象的大小,但是这不被Google的C++类型规范所提倡,这种情况下应当使用ASSERT_TRUE()
或者EXPECT_TRUE()
来进行判断。不过还是应当尽可能的使用ASSERT_EQ(actual, expected)
,因为他能够在测试失败时告知actual
和expected
的值。
ASSERT_EQ()
在比较指针时比较的是指针的值,当比较两个C风格的字符串时,将会比较他们是否有相同的内存地址,而不是有相同的值。因此在比较C风格字符串的时候应当使用ASSERT_STREQ()
,但是在比较两个string对象的时候,应当使用ASSERT_EQ
。
在进行指针的比较时应当使用*_EQ(ptr, nullptr)
和*_NE(ptr, nullptr)
代替*_EQ(ptr, NULL)
和*_NE(ptr, NULL)
,因为nullptr
被定义了类型而NULL
却没有。
当比较浮点数时应该使用浮点数断言来避免近似值导致的问题。
本节的宏定义对string
和wstring
都适用。
ps:2016年二月前的GTEST版本对*_EQ
断言有着ASSERT_EQ(expected, actual)
这样的顺序要求,但是新的*_EQ
对两个参数顺序没有要求。
字符串比较
这节的断言用来比较C语言风格的字符串,在比较两个string对象时,应该使用EXPECT_EQ
,EXPECT_NE
。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_STREQ(str1,str2); | EXPECT_STREQ(str1,str2); | the two C strings have the same content |
ASSERT_STRNE(str1,str2); | EXPECT_STRNE(str1,str2); | the two C strings have different contents |
ASSERT_STRCASEEQ(str1,str2); | EXPECT_STRCASEEQ(str1,str2); | the two C strings have the same content, ignoring case |
ASSERT_STRCASENE(str1,str2); | EXPECT_STRCASENE(str1,str2); | the two C strings have different contents, ignoring case |
注意:“CASE”表明忽略大小写,一个NULL
指针和空字符串不一样
创建一个测试:
TEST()
宏定义来定义和命名一个测试函数,这些宏就是没有返回值的普通C++函数。TEST(TestSuiteName, TestName) {
... test body ...
}
TEST()
的第一个参数是测试套件(Test Suite)的名称,第二个参数是这个测试套件中该测试(Test)的名称。两种名称都必须是合法的C++标识符,并且不能包含任何下划线_
。不同测试套件中的测试可以有相同的名字。
举个例子,被测函数是一个简单的斐波那契函数:
int Factorial(int n); // Returns the factorial of n
一个测试可以写成:
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(Factorial(0), 1);
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(Factorial(1), 1);
EXPECT_EQ(Factorial(2), 2);
EXPECT_EQ(Factorial(3), 6);
EXPECT_EQ(Factorial(8), 40320);
}
逻辑上来说,相关的测试应该在同一个测试套件(Test Suite)中。在上述的例子中,有两个测试HandlesZeroInput
和HandlesPositiveInput
,他们属于同一个测试套件FactorialTest
。
当两个或更多的测试需要使用相似的数据时,可以使用Test Fixture。这可以对不同的测试重用相同的数据对象配置。
创建一个fixture:
::testing::Test
派生出一个类。用protected:
开始它的类主体,因为需要从子类访问fixture成员。SetUp()
函数来为每个测试准备对象。常见的错误是将SetUp()
拼写为Setup()
,在c++ 11中可以使用override
来确保拼写正确。TearDown()
函数以释放您在SetUp()
中分配的所有资源。 若要了解何时应使用构造函数/析构函数以及何时应使用SetUp()/ TearDown()
,请阅读[FAQ][www.baidu.com]。当使用fixture时,使用TEST_F()
代替TEST()
,因为TEST_F()
允许你在Test Fixture中获取对象和子程序:
TEST_F(TestFixtureName, TestName) {
... test body ...
}
和TEST()
类似,第一个参数是测试套件的名字,但是TEST_F()
的这个参数必须和Test Fixture
类的名字相同。还需要在使用Test Fixture
对象之前定义这个Test Fixture
类,否则会导致编译错误virtual outside class declaration
。
对于每个TEST_F()
来说,GTEST在运行时都会创建一个新的test fixture对象,并且通过SetUp()
立刻初始化这个对象,再运行测试,结束后通过调用TearDown()
来进行清理工作,最后将删除这个test fixture对象。注意,在同一个测试套件中的不同测试拥有不同的test fixture对象,GTEST在新建下一个test fixture对象时总是会先删除上一个test fixture对象,并且不会在多个不同的测试中重用一个test fixture对象。所以如果任何测试改变了它的test fixture对象,并不会影响其他测试的test fixture对象。
下面用对一个FIFO队列类Queue
编写测试,他有以下接口:
template <typename E> // E is the element type.
class Queue {
public:
Queue();
void Enqueue(const E& element);
E* Dequeue(); // Returns NULL if the queue is empty.
size_t size() const;
...
};
定义一个fixture类。按照惯例,应该给它起一个FooTest
的名字,其中Foo
是被测试的类。
class QueueTest : public ::testing::Test {
protected:
void SetUp() override {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// void TearDown() override {}
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
在这个例子中,不需要TearDown()
函数,因为析构器已经完成了析构工作,不需要再进行清理。
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(q0_.size(), 0);
}
TEST_F(QueueTest, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(n, nullptr);
n = q1_.Dequeue();
ASSERT_NE(n, nullptr);
EXPECT_EQ(*n, 1);
EXPECT_EQ(q1_.size(), 0);
delete n;
n = q2_.Dequeue();
ASSERT_NE(n, nullptr);
EXPECT_EQ(*n, 2);
EXPECT_EQ(q2_.size(), 1);
delete n;
}
上面使用了ASSERT_*
和EXPECT_*
断言。当希望测试在断言失败后继续显示更多错误时使用EXPECT_*
,而在失败后继续运行测试没有意义则使用ASSERT_*
。例如,Dequeue测试中的第二个断言是ASSERT_NE(nullptr, n)
,因为我们稍后需要对指针n
进行解引用,这将在n
的值为NULL
时导致段错误。
当测试运行时,以下步骤将会发生:
QueueTest
对象t1
t1.SetUp()
初始化t1
t1
上运行t1.TearDown()
在第一个测试结束时进行清理t1
QueueTest
对象测试DequeueWorks
测试时,重复上述步骤TEST()
和TEST_F()
向googletest隐式注册其测试。与许多其他C ++测试框架不同,不必重新列出所有已定义的测试即可运行它们。
定义测试后,可以使用RUN_ALL_TESTS()
运行它们,如果所有测试成功,将返回0,否则返回1。RUN_ALL_TESTS()
在链接单元中运行所有测试,它们可以来自不同的测试套件,甚至来自不同的源文件。
当调用RUN_ALL_TESTS()
宏时:
SetUp()
初始化这个对象TearDown()
函数进行清理当一个致命性的错误发生时,后续的步骤将会被跳过。
重要说明:一定不能忽略
RUN_ALL_TESTS()
的返回值,否则会出现编译器错误。 这种设计的基本原理是,自动化测试服务将根据其退出代码(而不是根据其stdout / stderr输出)来确定测试是否通过。 因此main()
函数必须返回RUN_ALL_TESTS()
的值。另外,您应该只调用一次
RUN_ALL_TESTS()
。 多次调用它会与某些高级googletest功能(例如线程安全的死亡测试)发生冲突,因此不被支持。
gtest_main
库提供了一个合适的程序入口点,通过链接gtest_main
动态库而不是gtest
库,大多用户无需编写他们自己的main函数(Google Test提供了main()
函数的基本实现。如果适合你的需求,则只需将测试与gtest_main库链接就可以了。)。本节的其余部分仅适用于需要在测试运行前做一些自定义的事情,而这些事情不能在test fixture和测试套件的框架内表达。
如果您编写自己的main()
函数,则该函数应返回RUN_ALL_TESTS()
的值。
下面是一个模板:
#include "this/package/foo.h"
#include "gtest/gtest.h"
namespace my {
namespace project {
namespace {
// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
protected:
// You can remove any or all of the following functions if their bodies would
// be empty.
FooTest() {
// You can do set-up work for each test here.
}
~FooTest() override {
// You can do clean-up work that doesn't throw exceptions here.
}
// If the constructor and destructor are not enough for setting up
// and cleaning up each test, you can define the following methods:
void SetUp() override {
// Code here will be called immediately after the constructor (right
// before each test).
}
void TearDown() override {
// Code here will be called immediately after each test (right
// before the destructor).
}
// Class members declared here can be used by all tests in the test suite
// for Foo.
};
// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
const std::string input_filepath = "this/package/testdata/myinputfile.dat";
const std::string output_filepath = "this/package/testdata/myoutputfile.dat";
Foo f;
EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0);
}
// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
// Exercises the Xyz feature of Foo.
}
} // namespace
} // namespace project
} // namespace my
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
:: testing :: InitGoogleTest()
函数解析命令行中的googletest标志,并删除所有可识别的标志。这允许用户通过各种标志控制测试程序的行为,将在AdvancedGuide中介绍这些标志。 注意,必须在调用RUN_ALL_TESTS()
之前调用该函数,否则标志将无法正确初始化。
GTEST被设计成线程安全的。在使用pthread
的系统上,GTEST的实现是线程安全的,而在其他系统(如Windows)上多线程并发使用Google Test
的断言并不安全。一般情况下断言都是在主线程中进行的,因此在绝大多数测试中这并不会产生问题。
2人点赞
作者:愿以光散黑
链接:https://www.jianshu.com/p/c7c702c0abb9
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
GoogleMock是个很强大的东西,测试一个模块的时候,可能涉及到和其他模块交互,可以将模块之间的接口mock起来,模拟交互过程。
1. Makefile里面需要加入 -lgmock才能正常连接
?AM_LDFLAGS=-lpthread -lc -lm -lrt -lgtest -lgmock?
2. 可以手工生成Mock类,也可以使用脚本生成
手工:
class ObProject: public ObSingleChildPhyOperator
{ ??
? ?public:
? ? ? ? ObProject();
? ? ? ? virtual ~ObProject();
? ? ? ? void reset(){};
?
?
? ? ? ? int add_output_column(const ObSqlExpression& expr);
? ? ? ? virtual int open();
? ? ? ? virtual int close();
? ? ? ? virtual int get_next_row(const common::ObRow *&row);
? ? ? ? virtual int64_t to_string(char* buf, const int64_t buf_len) const;
? ? ? ? ....
?};
?
class MockObProject : public ObProject
?
{
? public:
? MOCK_METHOD0(open, int());
? MOCK_METHOD0(close, int());
? MOCK_METHOD1(add_output_column, int(const ObSqlExpression &expr));
};
脚本:
需要mock ob_ms_tablet_location_proxy.h中的ObMergerLocationCacheProxy类,方法如下:
?gmock_installed_dir/scripts/generator/gmock_gen.py ob_ms_tablet_location_proxy.h ObMergerLocationCacheProxy
3. 一个类中,只有virtual的member funciton能被mock(试验得到的结论),调用被mock的member function,function行为变成mocked behavior,调用类中没有被mock的member function,function行为与原类相同,不被mock改变。
ps,写了一个简单类,不是virtual居然也能被mock,奇怪。。。。在一个复杂类中,必须是virtual的才能被mock。 这些是实验得到的结论。
从理论上分析,应该必须是virtual才可以。所以,确定哪些函数要被mock,然后在头文件中将其virtual化。不然可别说我没有预先告诉你哦;)
4. 一个被Mock的函数,如果没有在EXPECT_CALL中指定expected behavior,系统将会为其指派默认行为(什么都不做,返回0),并且在屏幕上打印WARNING:
GMOCK WARNING:
Uninteresting mock function call - returning default value.
? ? Function call: get_next_row(@0x7fff51a6b888 0x30c51529e0)
? ? ? ? ? Returns: 0
Stack trace:
摘抄自:https://blog.csdn.net/maray/article/details/7750617
|
开发测试 最新文章 |
pytest系列——allure之生成测试报告(Wind |
某大厂软件测试岗一面笔试题+二面问答题面试 |
iperf 学习笔记 |
关于Python中使用selenium八大定位方法 |
【软件测试】为什么提升不了?8年测试总结再 |
软件测试复习 |
PHP笔记-Smarty模板引擎的使用 |
C++Test使用入门 |
【Java】单元测试 |
Net core 3.x 获取客户端地址 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年4日历 | -2025/4/4 3:32:31- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |