如何使用 Google Test 测试大量数据结构的方法?
How to test methods of heavy data structures using Google Test?
假设我们有以下 class:
class Graph {
public:
Graph(int num_vertices, int num_edges, const EdgeList& edge_list)
: num_vertices_(num_vertices), num_edges_(num_edges), edge_list_(edge_list) { }
int GetNumberOfComponents() { ... }
private:
int num_vertices_;
int num_edges_;
EdgeList edge_list;
}
在文件gtest.cpp中我有这样的东西:
#include "gtest/gtest.h"
TEST(Test, NumberOfComponentsTest) {
Graph graph(4, 3, {{1, 2}, {2, 3}, {1, 3}});
EXPECT_EQ(2, graph.GetNumberOfComponents());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
目标是使用 Google 测试框架检查 GetNumberOfComponents()
是否正常工作。
但是让我们考虑大型测试用例,例如 num_vertices = 1000
、number_edges = 100000
。如果我不想硬编码所有边,在这种情况下如何编写这样的测试? ;)
如果您不想对大图进行硬编码,那么您需要一种确定性的方法来在 运行 时生成它。从文件读取会产生文件系统依赖性并减慢测试速度。
这个问题其实隐藏了两个问题:
- 我真正在测试什么?
- 假设我决定我真的需要来测试 100K 条边,最好的方法是什么?
从我的观点和经验来看,最重要的问题是1:
- 我在测试性能吗?那么是的,我需要测试 100K 边缘情况(并测量时间或其他资源使用情况)。
- 我是否在测试边界条件并且我知道该实现具有大约 100K 个边的条件代码?那么是的,我需要测试这个案例。
- 我是否正在测试稳健性或安全性并且我有理由认为我可能能够用 100K 边缘破坏被测系统?那么是的,我需要测试这个案例。
- 另一方面,如果我 "just" 测试正确性,为什么我觉得测试 10 条边不足以说服自己该实现也适用于 100K 条边?在继续之前我需要回答这个问题。
做个比较:假设我正在测试一个 returns 数字列表总和的函数。假设我要测试 0,1 和 5 元素的列表。为什么我认为 5 个元素不足以代表一般情况?
我想说的是首先一个人必须真正理解什么一个人在测试为什么,在进入测试编码之前。
对于问题2,我觉得robert的回答是对的,我只能转述一下。您需要编写一个 尽可能简单的 辅助函数来在 运行 时生成图形。
但是从代码来看,Graph
class 的设计问题似乎应该在之前解决:
- 既然构造函数需要边列表,为什么在参数
num_edges
中还需要边列表的大小?该实现可以轻松地从列表本身获取列表的大小。
- 此外,要求顶点数量的事实也是有问题的,总是出于与接收边列表相同的原因。顶点数应该是从边列表计算出来的,否则如果
num_vertices
和从边列表计算出的顶点数不一致怎么办?
您正在编写测试这一事实非常好,因为测试迫使您质疑 Graph
的设计。考虑一下并考虑重新设计,使用其他更简单的测试来指导您的设计。
假设我们有以下 class:
class Graph {
public:
Graph(int num_vertices, int num_edges, const EdgeList& edge_list)
: num_vertices_(num_vertices), num_edges_(num_edges), edge_list_(edge_list) { }
int GetNumberOfComponents() { ... }
private:
int num_vertices_;
int num_edges_;
EdgeList edge_list;
}
在文件gtest.cpp中我有这样的东西:
#include "gtest/gtest.h"
TEST(Test, NumberOfComponentsTest) {
Graph graph(4, 3, {{1, 2}, {2, 3}, {1, 3}});
EXPECT_EQ(2, graph.GetNumberOfComponents());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
目标是使用 Google 测试框架检查 GetNumberOfComponents()
是否正常工作。
但是让我们考虑大型测试用例,例如 num_vertices = 1000
、number_edges = 100000
。如果我不想硬编码所有边,在这种情况下如何编写这样的测试? ;)
如果您不想对大图进行硬编码,那么您需要一种确定性的方法来在 运行 时生成它。从文件读取会产生文件系统依赖性并减慢测试速度。
这个问题其实隐藏了两个问题:
- 我真正在测试什么?
- 假设我决定我真的需要来测试 100K 条边,最好的方法是什么?
从我的观点和经验来看,最重要的问题是1:
- 我在测试性能吗?那么是的,我需要测试 100K 边缘情况(并测量时间或其他资源使用情况)。
- 我是否在测试边界条件并且我知道该实现具有大约 100K 个边的条件代码?那么是的,我需要测试这个案例。
- 我是否正在测试稳健性或安全性并且我有理由认为我可能能够用 100K 边缘破坏被测系统?那么是的,我需要测试这个案例。
- 另一方面,如果我 "just" 测试正确性,为什么我觉得测试 10 条边不足以说服自己该实现也适用于 100K 条边?在继续之前我需要回答这个问题。
做个比较:假设我正在测试一个 returns 数字列表总和的函数。假设我要测试 0,1 和 5 元素的列表。为什么我认为 5 个元素不足以代表一般情况?
我想说的是首先一个人必须真正理解什么一个人在测试为什么,在进入测试编码之前。
对于问题2,我觉得robert的回答是对的,我只能转述一下。您需要编写一个 尽可能简单的 辅助函数来在 运行 时生成图形。
但是从代码来看,Graph
class 的设计问题似乎应该在之前解决:
- 既然构造函数需要边列表,为什么在参数
num_edges
中还需要边列表的大小?该实现可以轻松地从列表本身获取列表的大小。 - 此外,要求顶点数量的事实也是有问题的,总是出于与接收边列表相同的原因。顶点数应该是从边列表计算出来的,否则如果
num_vertices
和从边列表计算出的顶点数不一致怎么办?
您正在编写测试这一事实非常好,因为测试迫使您质疑 Graph
的设计。考虑一下并考虑重新设计,使用其他更简单的测试来指导您的设计。