1 引言
1.1 Google Mock简介
Google Mock是由Google开发的一种用于C++的模拟(mocking)框架,它是Google Test测试框架的一部分。gmock允许开发者创建模拟对象,这些对象可以在单元测试中代替真实的依赖项,使得测试更加灵活和独立。通过使用gmock,开发者可以专注于测试代码逻辑的正确性,而不必担心外部依赖的复杂性。
1.2为什么选择Google Mock
在众多C++测试框架中,gmock以其强大的功能和易用性脱颖而出。以下是选择gmock的一些主要理由:
l灵活性:gmock支持高度定制化的模拟行为,可以模拟复杂的依赖关系。
l易用性:gmock的API设计简洁直观,易于学习和使用。
l社区支持:作为Google的产品,gmock拥有活跃的社区和丰富的文档资源。
l集成性:gmock可以与Google Test无缝集成,提供一站式的测试解决方案。
2 Google Mock基础
2.1 测试的重要性
在深入探讨Google Mock之前,我们首先要认识到测试在软件开发中的重要性。测试是确保软件质量的关键环节,它帮助我们发现并修复潜在的错误和缺陷。单元测试是测试中最基本的形式,它允许我们独立地测试代码的各个部分。
2.2 Google Mock的安装和配置
在开始使用Google Mock之前,我们需要先进行安装和配置。以下是安装Google Mock的基本步骤:
1.获取Google Test:由于Google Mock是Google Test的一部分,我们需要先获取Google Test的源代码。
2.编译Google Test:根据你的操作系统和编译器,编译Google Test库。
3.配置项目:在你的项目中配置Google Test和Google Mock的头文件路径和库路径。
2.3 测试用例的结构
一个典型的测试用例通常包括以下几个部分:
l测试构建:设置测试所需的环境和条件。
l执行测试:运行被测试的代码。
l断言:验证代码的输出是否符合预期。
l清理:测试完成后清理环境。
class MyMathTest : public ::testing::Test {
protected:
void SetUp() override {
// 测试构建
}
void TearDown() override {
// 清理
}
};
TEST_F(MyMathTest, TestAddition) {
// 执行测试
int result = 3 + 2;
// 断言
EXPECT_EQ(5, result);
}
2.4编写测试用例的步骤
编写测试用例通常遵循以下步骤:
1.确定测试目标:明确你想要测试的代码部分或功能。
2.编写测试代码:使用Google Test的宏和断言来编写测试逻辑。
3.运行测试:编译并运行测试,查看结果是否符合预期。
4.分析和调整:根据测试结果调整测试用例或被测试的代码。
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
3 创建测试用例
3.1 测试用例的重要性
测试用例是单元测试的核心,它们定义了测试的输入、执行过程和预期结果。编写高质量的测试用例可以确保你的代码在修改和扩展过程中保持稳定和可靠。
3.2 测试用例的基本原则
在编写测试用例时,应遵循以下基本原则:
l独立性:每个测试用例应独立于其他测试用例运行,不应依赖外部状态。
l可重复性:无论何时何地运行测试用例,都应得到相同的结果。
l自动化:测试用例应自动化执行,减少人工干预。
l覆盖全面:测试用例应覆盖所有重要的功能点和边界条件。
3.3 测试用例的结构
一个完整的测试用例通常包括以下部分
l前置条件:测试开始前需要满足的条件。
l输入数据:测试用例的输入。
l执行步骤:执行测试的具体步骤。
l预期结果:测试完成后期望的结果。
l验证逻辑:验证实际结果是否符合预期结果的逻辑。
3.4 示例:简单的加法测试用例
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
3.5测试用例的参数化
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
class AdderTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};
TEST_P(AdderTest, AddReturnsExpectedResult) {
Adder adder;
int a, b, expected;
std::tie(a, b, expected) = GetParam();
EXPECT_EQ(expected, adder.add(a, b));
}
INSTANTIATE_TEST_CASE_P(AdderTests, AdderTest,
::testing::Values(std::make_tuple(2, 3, 5),
std::make_tuple(-2, 1, -1),
std::make_tuple(0, 0, 0)));
3.6 测试用例的组织
在大型项目中,合理组织测试用例非常重要。通常,测试用例应该按照它们测试的类或模块来组织。使用命名约定和目录结构可以帮助维护和查找测试用例。
3.7 示例:测试复杂逻辑
让我们考虑一个更复杂的例子,测试一个简单的银行账户类:
class BankAccount {
public:
BankAccount(int balance) : balance_(balance) {}
void deposit(int amount) { balance_ += amount; }
int getBalance() const { return balance_; }
private:
int balance_;
};
TEST(BankAccountTest, DepositIncreasesBalance) {
BankAccount account(100);
account.deposit(50);
EXPECT_EQ(150, account.getBalance());
}
TEST(BankAccountTest, DepositWithNegativeAmountThrows) {
BankAccount account(100);
account.deposit(-50);
EXPECT_EQ(50, account.getBalance());
}
4、Mocking的基本概念
4.1 什么是Mocking?
Mocking是一种测试技术,它允许测试者模拟(mock)一个对象或接口的行为,以便在测试中隔离被测试的代码。Mock对象通常用于替代真实的依赖项,使得测试可以独立于外部系统或组件运行。
4.2 Mocking与Stub的区别
lMock:通常用于验证被测试代码对依赖项的调用是否正确,包括调用次数、参数、调用顺序等。
lStub:返回预定义的响应数据,主要用于测试代码的逻辑,而不是验证调用的正确性。
4.3 为什么使用Mocking?
l隔离性:Mocking允许测试独立于外部系统运行,提高了测试的稳定性和可靠性。
l灵活性:可以模拟各种复杂的情况,包括错误、异常、延迟等。
l效率:避免了与外部系统的交互,加快了测试执行的速度。
4.4 使用Google Mock进行Mocking
Google Mock提供了一套丰富的API来创建和配置Mock对象。以下是使用Google Mock进行Mocking的基本步骤:
1.定义Mock接口:根据需要Mock的类或接口定义一个Mock版本。
2.使用MOCK_METHOD宏:在Mock接口中定义Mock方法。
3.设置期望:使用EXPECT_CALL来设置Mock对象的期望行为。
4.验证调用:在测试结束时,Google Mock会自动验证Mock对象的调用是否符合期望。
4.5示例:Mock一个简单的依赖
#include <gtest/gtest.h>
class Database {
public:
virtual ~Database() {}
virtual std::string query(const std::string& sql) const{return sql;}
};
class MockDatabase:public Database {
public:
MOCK_METHOD(std::string, query, (const std::string& sql), (const, override));
};
class DataProcessor {
public:
explicit DataProcessor(Database* db) : db_(db) {}
std::string process(const std::string& data) {
return data + " processed with " + db_->query("SELECT * FROM table");
}
private:
Database* db_;
};
TEST(DataProcessorTest, ProcessesDataWithDatabaseQuery) {
MockDatabase mockDb;
DataProcessor processor(&mockDb);
EXPECT_CALL(mockDb, query("SELECT * FROM table"))
.WillOnce(testing::Return("Mocked query result"));
std::string result = processor.process("Data");
EXPECT_EQ("Data processed with Mocked query result", result);
}
4.6 高级Mocking技巧
l序列化调用:使用EXPECT_CALL的InSequence来模拟方法调用的顺序。
l任意次数的调用:使用Times()来指定方法可以被调用的次数范围。
l组合Mock和Stub:在同一个Mock对象中同时使用Mock和Stub的行为。
4.6.1使用Mock验证方法调用顺序
1) 期望全部顺序调用
using ::testing::_;
using ::testing::InSequence;
class MyClass {
public:
virtual bool firstMethod(int){return true;}
virtual bool secondMethod(int){return true;}
};
class MockMyClass {
public:
MOCK_METHOD(bool, firstMethod,(int));
MOCK_METHOD(bool, secondMethod,(int));
};
TEST(SomeClassTest, CallsMethodsInOrder) {
MockMyClass mock;
{
InSequence seq;
EXPECT_CALL(mock, firstMethod(testing::_))
.WillOnce(testing::Return(true));
EXPECT_CALL(mock, secondMethod(testing::_))
.WillOnce(testing::Return(true));
}
//EXPECT_EQ(true, mock.firstMethod(1));
//EXPECT_EQ(true, mock.secondMethod(2));
EXPECT_EQ(true, mock.secondMethod(2));
EXPECT_EQ(true, mock.firstMethod(1));
}
按照如上代码执行将报错
[ FAILED ] SomeClassTest.CallsMethodsInOrder (1 ms)
[----------] 1 test from SomeClassTest (1 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (1 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] SomeClassTest.CallsMethodsInOrder
如果先执行mock.firstMethod(1),再执行mock.secondMethod(2)就正确了。
2)期望部分顺序调用
EXPECT_CALL的After从句可以执行按部分顺序调用。
通过使用InSequence()从句
using ::testing::Sequence;
...
Sequence s1, s2;
EXPECT_CALL(foo, A()).InSequence(s1, s2);
EXPECT_CALL(bar, B()).InSequence(s1);
EXPECT_CALL(bar, C()).InSequence(s2);
EXPECT_CALL(foo, D()).InSequence(s2);
执行顺序
按如下图的方式 (where s1 is A -> B, and s2 is A -> C -> D):
S1:A--------B
|
S2:A--------C ---------D
4.6.2任意次数的调用
EXPECT_CALL(mock_object,method_name(matchers...)) 创建一个mock对象mock_object,这个对象有一个名为method_name的方法,方法的参数为matchers…。EXPECT_CALL必须在任何mock对象之前使用。以下方法的调用,必须按以下顺序进行:
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
0
4.6.3 组合Mock和Stub
在同一个Mock对象中,我们可以同时使用Mock和Stub的行为,这可以让我们在不同的测试场景下灵活地控制Mock对象的行为。
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
1
4.7 Mocking复杂类型
有时我们需要Mock返回复杂类型的方法。Google Mock提供了NiceMock和StrictMock等工厂函数,它们可以简化Mock对象的创建和配置。
4.7.1NiceMock
NiceMock 是 Google Mock (gmock) 提供的一个包装器,它允许你创建更为"宽容"的模拟对象。与 StrictMock 不同,NiceMock 不会对未指定的调用产生错误,而是会默认生成一个合适的返回值或者行为。
以下是一个简单的 NiceMock 示例:
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
2
4.7.2 StrictMock
StrictMock是 Google Mock (gmock) 提供的另一个包装器,与 NiceMock 不同,StrictMock 对未指定的调用会报错。这意味着你必须为 mock 对象的所有方法指定期望行为,否则如果在测试期间调用了未设置期望的方法,测试将会失败。以下是一个使用 StrictMock 的示例:
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
3
l使用NiceMock方法,尝试调用未设置期望的mock方法,测试将失败;
l使用StrictMock方法,尝试调用未设置期望的mock方法,测试将失败。
5、高级Mocking技巧
5.1 引言
高级Mocking技巧是单元测试中的进阶技能,它可以帮助测试者更精确地模拟复杂场景,从而提高测试的覆盖率和质量。在本部分,我们将深入探讨一些高级Mocking技巧,并通过丰富的示例来展示它们的应用。
5.2 使用ON_CALL自定义Mock行为
ON_CALL宏允许我们为Mock对象的方法指定默认行为,这在测试中非常有用,特别是当Mock对象的方法需要在不同的测试用例中重复调用时。
签名:
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
4
定义了调用mock_object对象的method_name方法后执行的动作。如果matchers被忽略了,类似于每个参数都是"_",即可以匹配任意值。
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
5
lWith(multi_argument_matcher):将参数作为整体匹配。GoogleTest将所有参数作为一个tuple给matcher,multi_argument_matcher最终将是Matcher<std::tuple<A1, …, An>>。这个调用最多一次
lWillByDefault(action):指定调用mock函数后执行的动作。这个调用有且只有一次。
看一个例子
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
6
5.3 模拟异常
在某些情况下,我们可能需要模拟方法抛出异常,以测试被测试对象对异常的处理能力。
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
7
通过testing::Throw和EXPECT_THROW来模拟异常。
5.4 使用Invoke回调函数
Invoke函数允许我们在Mock方法中调用一个回调函数,这在需要根据输入参数动态返回结果时非常有用。
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
8
5.5 模拟复杂的数据结构
当Mock方法返回复杂的数据结构时,我们可以使用WithArgs来匹配特定的参数,并返回对应的结果。
class NetworkService {
virtual std::string fetchData(){return "";}
};
class MockNetworkService : public NetworkService {
public:
MOCK_METHOD(std::string, fetchData, (), (override));
};
TEST(NetworkServiceTest, FetchDataTest) {
MockNetworkService mockService;
EXPECT_CALL(mockService, fetchData())
.WillOnce(testing::Return("Mocked Data"));
std::string result = mockService.fetchData();
EXPECT_EQ("Mocked Data", result);
}
9
5.6 模拟方法调用的副作用
有时,我们可能需要模拟方法调用时产生的副作用,例如修改共享状态或触发回调。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
0
5.7 模拟方法的多次调用
使用Times可以指定Mock方法被调用的次数,这对于测试循环或递归逻辑非常有用。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
1
5.8 使用UnorderedElementsAre匹配容器
当Mock方法的参数是容器时,我们可以使用UnorderedElementsAre来匹配容器中的元素,而不需要指定元素的顺序。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
2
6、Google Mock的断言和期望
6.1 断言的重要性
断言是单元测试中验证代码逻辑正确性的关键工具。它们允许测试者指定预期结果,并在结果不符合预期时立即报告错误。
6.2 基本断言Google Test
提供了一系列基本断言,用于验证测试结果是否符合预期。
lASSERT_TRUE:如果条件为假,则测试失败。
lEXPECT_TRUE:同上,但条件为假时测试继续执行。
lASSERT_EQ:验证两个值是否相等,如果不相等则测试失败。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
3
6.3 期望调用(Expectations)
期望调用是 Google Mock 中用于指定 Mock 对象在测试中应该如何被调用的机制。
lEXPECT_CALL:创建一个期望调用。
lTimes:指定期望调用的次数。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
4
6.4 匹配器(Matchers)
Google Mock 提供了丰富的匹配器,允许我们在期望调用中使用复杂的条件。
ltesting::_:匹配任何值。
ltesting::Eq(x):匹配等于x的值。
ltesting::Le(x):匹配小于x的值。
ltesting::Ge(x):匹配大于或等于 x 的值。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
5
6.5 组合断言
组合断言允许我们构建更复杂的验证逻辑。
ltesting::AllOf:所有条件都满足。
ltesting::AnyOf:任一条件满足。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
6
6.6断言动作(Actions)
断言动作是 Google Mock 中用于指定 Mock 对象在期望调用发生时应该执行的操作。
ltesting::Return(x):返回值 x。
ltesting::Throw:抛出异常。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
7
6.7 验证器(Validators)
验证器允许我们在 Mock 对象的调用发生时执行自定义验证逻辑。
ltesting::SaveArg:保存调用参数。
ltesting::InvokeWithoutArgs:调用无参函数。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
8
6.8 期望和断言的高级用法
高级用法包括设置期望的顺序、使用参数化期望等。
•InSequence:确保调用按特定顺序发生。
•testing::Each:匹配每个元素。
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
TEST(AdderTest, HandlesPositiveNumbers) {
Adder adder;
EXPECT_EQ(5, adder.add(2, 3));
}
TEST(AdderTest, HandlesNegativeNumbers) {
Adder adder;
EXPECT_EQ(-1, adder.add(-2, 1));
}
TEST(AdderTest, HandlesZero) {
Adder adder;
EXPECT_EQ(0, adder.add(0, 0));
}
9
7 整合
从以上案例来看。可以整合计算器和数据访问两个程序。
7.1 计算器
Calculator.cpp
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
class AdderTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};
TEST_P(AdderTest, AddReturnsExpectedResult) {
Adder adder;
int a, b, expected;
std::tie(a, b, expected) = GetParam();
EXPECT_EQ(expected, adder.add(a, b));
}
INSTANTIATE_TEST_CASE_P(AdderTests, AdderTest,
::testing::Values(std::make_tuple(2, 3, 5),
std::make_tuple(-2, 1, -1),
std::make_tuple(0, 0, 0)));
0
7.2数据库访问
Database.cpp
class Adder {
public:
int add(int a, int b) {
return a + b;
}
};
class AdderTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};
TEST_P(AdderTest, AddReturnsExpectedResult) {
Adder adder;
int a, b, expected;
std::tie(a, b, expected) = GetParam();
EXPECT_EQ(expected, adder.add(a, b));
}
INSTANTIATE_TEST_CASE_P(AdderTests, AdderTest,
::testing::Values(std::make_tuple(2, 3, 5),
std::make_tuple(-2, 1, -1),
std::make_tuple(0, 0, 0)));
1
本书第1章与第2章介绍软件单元测试的概念和基础知识。
第1章简单介绍软件单元测试所包含的概念,包括桩对象和测试驱动函数、测试驱动开发、软件测试贯彻始终、软件测试金字塔、单元测试在传统/敏捷开发模式中的地位、精准测试、单元测试和白盒测试,以及单元测试的FIRST原则和AIR原则。
第2章介绍软件单元测试基础知识,包括动态自动化/手工单元测试、静态自动化/手工单元测试。在动态自动化单元测试中介绍了语句覆盖、分支覆盖、条件覆盖、条件/分支覆盖、MC/DC、路径覆盖和控制流覆盖。
第3章到第5章介绍C语言、Java语言和Python语言的单元测试框架。
第3章介绍C语言动态自动化单元测试框架,包括在Windows下安装C语言运行环境、在Windows和Linux下安装编译CUnit、查看测试报告、CUnit介绍和案例。
第4章介绍Java语言动态自动化单元测试框架,包括在Eclipse中创建Maven项目和配置JUnit与TestNG运行环境、JUnit 4测试框架、JUnit 5测试框架、TestNG测试框架、测试替身、变异测试、利用EvoSuite自动生成测试用例,以及在Jenkins中配置JUnit 4、JUnit 5、TestNG和Allure。
第5章介绍Python语言动态自动化单元测试框架,包括unittest、Pytest及Python的模拟对象和变异测试工具mutpy。
第6章与第7章介绍代码覆盖率工具和代码语法规范检查工具。
第6章介绍代码覆盖率工具,包括C语言覆盖率工具gcov和lcov、Java语言覆盖率工具JaCoCo,以及Python语言覆盖率工具Coverage和pytest-cov。
第7章介绍代码语法规范检查工具,包括Java语言静态分析工具PMD、Python语言静态分析工具flake8和pylint,以及多代码语法规范检查平台SonarQube。
第8章通过两个案例详细介绍TDD。
读者可以根据自己的需求对以上内容进行选择性阅读或者全部阅读。另外,为了巩固大家的学习效果,每一章结尾都有相应的习题。
顾翔凡言:人工智能未来的发展瓶颈在于对知识的更新。唯一不变的是变化,知识发生了变化,人工智能软件能否及时跟进变化,可能 阻碍人工智能的使用。
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...