简单测试
使用TEST()宏,其中第一个参数是测试套件名称(对应具体功能),第二个参数是测试用例名称(测试方向,比如测试判断是否为质数的函数,就有测试小数,测试负数,测试正数这三个反向),二者都必须是合法的C++标识符,并且不应该包含下划线。
#include <gtest/gtest.h>
#include "factorial.h"
// 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);
}
断言
GoogleTest断言是类似于函数调用的宏,用于测试类或函数的行为。当断言失败时,GoogleTest将打印断言所在的源文件、行数以及错误信息。
每个断言都有两种版本:ASSERT_版本的失败是致命失败(错误后测试案例里面剩下的语句不继续运行),EXPECT_版本的失败是非致命失败(错误后测试案例里面剩下的语句继续运行)。
断言 | 验证条件 |
---|---|
EXPECT_TRUE(condition) | condition为真 |
EXPECT_FALSE(condition) | condition为假 |
EXPECT_EQ(val1, val2) | val1 == val2 |
EXPECT_NE(val1, val2) | val1 != val2 |
EXPECT_LT(val1, val2) | val1 < val2 |
EXPECT_LE(val1, val2) | val1 <= val2 |
EXPECT_GT(val1, val2) | val1 > val2 |
EXPECT_GE(val1, val2) | val1 >= val2 |
EXPECT_STREQ(str1, str2) | C字符串str1和str2相等 |
EXPECT_STRNE(str1, str2) | C字符串str1和str2不相等 |
EXPECT_STRCASEEQ(str1, str2) | C字符串str1和str2相等,忽略大小写 |
EXPECT_STRCASENE(str1, str2) | C字符串str1和str2不相等,忽略大小写 |
EXPECT_FLOAT_EQ(val1, val2) | 两个float值val1和val2近似相等 |
EXPECT_DOUBLE_EQ(val1, val2) | 两个double值val1和val2近似相等 |
EXPECT_NEAR(val1, val2, abs_error) | val1和val2之差的绝对值不超过abs_error |
EXPECT_THROW(statement, exception_type) | statement抛出exception_type类型的异常 |
EXPECT_ANY_THROW(statement) | statement抛出任何类型的异常 |
EXPECT_NO_THROW(statement) | statement不抛出任何异常 |
EXPECT_THAT(val, matcher) | val满足匹配器matcher |
断言宏返回一个ostream对象,可以使用<<运算符输出自定义的失败信息。例如:
EXPECT_TRUE(my_condition) << "My condition is not true";
测试夹具
为什么需要测试夹具?为了让多个测试用例共用相同的对象或数据。
要创建一个fixture,只需继承::testing::Test类,在类中定义要使用的对象,在默认构造函数或SetUp()函数中进行初始化,在析构函数或TearDown()函数中进行清理(释放资源),此外还可以定义需要共用的函数。如下所示:
// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
protected:
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.
}
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.
};
要使用fixture类,使用TEST_F()宏而不是TEST()来定义测试。
为什么必须用TEST_F()?TEST_F()宏继承fixture类,TEST()继承::testing::Test。
TEST_F(TestFixtureName, TestName) {
test body
}
其中TestFixtureName既是fixture类名,也是测试套件名,在测试体中可以使用fixture类定义的数据成员。
对于每一个使用TEST_F()定义的测试,GoogleTest都会创建一个新的 fixture对象,调用SetUp()初始化,运行测试,调用TearDown()清理,最后删除fixture对象。同一个测试套件中的不同测试使用不同的fixture对象,因此一个测试所做的改变不影响其他测试。
Gmock(1.7以上的版本才有)
为什么要使用Gmock?
在测试中使用真实对象有时是不可行的,因为真实对象依赖昂贵的、不可靠的资源(例如数据库、网络连接等)使得测试变慢或不稳定。模拟对象(mock object)与真实对象实现相同的接口,但可以在运行时指定它将被如何使用(调用什么方法、以什么参数、调用多少次、以什么顺序)以及它应该做什么(返回什么值)。
示例
假设正在开发一个画图程序。要想测试程序是否正确,可以对比屏幕上的绘制结果和正确的屏幕截图,但这种方式太繁琐、难以维护。实际上,在测试中不需要真正调用系统接口在屏幕上绘制图形,只需验证是否调用了正确的接口即可。
假设程序使用的画图接口Turtle如下(类似于Python的turtle模块):
turtle.h
class Turtle {
public:
virtual ~Turtle() = default;
virtual void PenUp() = 0;
virtual void PenDown() = 0;
virtual void Forward(int distance) = 0;
virtual void Circle(int radius) = 0;
virtual void Turn(int degrees) = 0;
virtual void GoTo(int x, int y) = 0;
virtual void Head(int angle) = 0;
virtual int GetX() const = 0;
virtual int GetY() const = 0;
};
为Turtle接口编写mock类的步骤如下:
从Turtle派生一个类MockTurtle;
选择想要mock的虚函数;
在子类的public:部分对每个要mock的函数编写一个MOCK_METHOD()宏;
将函数签名复制粘贴到宏参数中,并分别在返回类型和函数名之间以及函数名和参数表之间添加一个逗号;
对于const成员函数,添加第4个宏参数(const);
覆盖虚函数建议添加override关键字:对于非const成员函数,第4个宏参数为(override);对于const成员函数,第4个宏参数为(const, override)。
#include <gmock/gmock.h>
#include "turtle.h"
class MockTurtle : public Turtle {
public:
~MockTurtle() override = default;
MOCK_METHOD(void, PenUp, (), (override));
MOCK_METHOD(void, PenDown, (), (override));
MOCK_METHOD(void, Forward, (int distance), (override));
MOCK_METHOD(void, Circle, (int radius), (override));
MOCK_METHOD(void, Turn, (int degrees), (override));
MOCK_METHOD(void, GoTo, (int x, int y), (override));
MOCK_METHOD(void, Head, (int angle), (override));
MOCK_METHOD(int, GetX, (), (const, override));
MOCK_METHOD(int, GetY, (), (const, override));
};
在测试中使用mock类
在测试中使用mock类的典型方式如下:
创建mock对象;
指定期望的调用方式(什么方法、以什么参数、被调用几次等),同时也可以指定方法被调用时的行为;
在被测函数中使用mock对象,同时也可以使用断言检查函数结果;
当mock对象被销毁时(测试函数返回前),gMock会自动检查期望的调用是否满足,如果不满足测试将会失败。
painter.h
#include "turtle.h"
class Painter {
public:
explicit Painter(Turtle* turtle): turtle_(turtle) {}
bool DrawLine(int x1, int y1, int x2, int y2);
bool DrawRectangle(int x, int y, int length, int width);
bool DrawCircle(int x, int y, int r);
private:
Turtle* turtle_;
};
painter.cc
#include "painter.h"
bool Painter::DrawLine(int x1, int y1, int x2, int y2) {
turtle_->GoTo(x1, y1);
turtle_->PenDown();
turtle_->GoTo(x2, y2);
turtle_->PenUp();
return true;
}
bool Painter::DrawRectangle(int x, int y, int length, int width) {
if (length <= 0 || width <= 0)
return false;
turtle_->GoTo(x, y);
turtle_->Head(270);
turtle_->PenDown();
turtle_->Forward(width);
turtle_->Turn(90);
turtle_->Forward(length);
turtle_->Turn(90);
turtle_->Forward(width);
turtle_->Turn(90);
turtle_->Forward(length);
turtle_->PenUp();
return true;
}
bool Painter::DrawCircle(int x, int y, int r) {
if (r <= 0)
return false;
turtle_->GoTo(x, y - r);
turtle_->Head(0);
turtle_->PenDown();
turtle_->Circle(r);
turtle_->PenUp();
return true;
}
painter_test.cc
#include <gmock/gmock.h>
#include "painter.h"
#include "mock_turtle.h"
using ::testing::AtLeast;
TEST(PainterTest, DrawCircle) {
MockTurtle turtle;
EXPECT_CALL(turtle, PenDown()).Times(AtLeast(1));
Painter painter(&turtle);
EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
}
该测试验证mock对象turtle的PenDown()方法将被调用至少一次,如果该方法最终没有被调用,则测试失败。
设置期望
gMock使用EXPECT_CALL()宏来对mock函数设置期望,通用语法为:
EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action)
;
Times()、WillOnce()和WillRepeatedly()这三个子句必须按顺序写。
匹配器:验证参数
匹配器(matcher)用于验证一个参数,可用于EXPECT_THAT()或EXPECT_CALL()断言。对于EXPECT_CALL(),匹配器由第二个参数中的参数表指定,用于验证mock函数的实际参数。
直接指定参数值表示期望参数等于指定的值:
// 期望turtle.Forward(100)被调用
EXPECT_CALL(turtle, Forward(100));
这里的100等价于Eq(100)。
通配符_表示任意值:
using ::testing::_;
// 期望turtle.GoTo(50, y)被调用,y为任意值
EXPECT_CALL(turtle, GoTo(50, _));
如果不对参数做任何限制,则可以省略参数表:
// 期望turtle.Forward(x)被调用,x为任意值
EXPECT_CALL(turtle, Forward);
// 期望turtle.GoTo(x, y)被调用,x和y为任意值
EXPECT_CALL(turtle, GoTo);
基数:验证调用次数
基数(cardinality)用于验证mock函数的调用次数,由EXPECT_CALL()后面跟着的Times()子句指定,至多使用一次。
直接指定数字表示恰好调用指定的次数:
// 期望turtle.Forward(100)被调用恰好两次
EXPECT_CALL(turtle, Forward(100)).Times(2);
AtLeast(n)表示至少被调用n次:
using ::testing::AtLeast;
// 期望turtle.PenDown()被调用至少一次
EXPECT_CALL(turtle, PenDown()).Times(AtLeast(1));
如果没有指定Times()子句,则gMock会按以下规则推断基数:
如果没有WillOnce()和WillRepeatedly(),则基数为Times(1)
如果有n个WillOnce()、没有WillRepeatedly(),其中n≥1,则基数为Times(n)
如果有n个WillOnce()、一个WillRepeatedly(),其中n≥0,则基数为Times(AtLeast(n))
动作:被调用时的行为
动作(action)用于指定mock函数被调用时的行为,也叫做打桩(stubbing)。
如果没有指定,则mock函数被调用时会执行默认动作:
void函数直接返回
返回类型是内置类型的函数返回对应类型的默认值:bool类型为false,数值类型为0,指针类型为nullptr
返回类型有默认构造函数的则返回默认构造的值
可以使用一个或多个WillOnce()子句以及一个可选的WillRepeatedly()子句指定动作。例如:
using ::testing::Return;
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillOnce(Return(300));
表示turtle.GetX()将被调用恰好三次分别返回100、200、300。
EXPECT_CALL(turtle, GetY())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillRepeatedly(Return(300));
表示turtle.GetY()将被调用至少两次,前两次分别返回100和200,之后返回300。
原文https://blog.csdn.net/zzy979481894/article/details/127177663?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171409665116800226554635%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171409665116800226554635&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_click~default-1-127177663-null-null.142v100pc_search_result_base6&utm_term=google%20test&spm=1018.2226.3001.4187
标签:turtle,调用,int,_-,GoogleTest,EXPECT,val1 From: https://www.cnblogs.com/cuberxh/p/18159510