googletest:sample3分析
待测文件
sample3
通过一个链表实现了一个队列(Queue)功能,队列的每个节点都是一个QueueNode对象. 链表没有虚拟头节点,head_
指向头节点,last_
指向尾节点.
对于Queue
类,实现了:
- 构造、析构;
- 插入元素(Enqueue)到队列末尾,从队列头弹出(Dequeue)元素;
- 队列数据清除(Clear);
- 队列大小的访问(Size);
- 队列头元节点的访问(Head),尾节点的访问(Last);
- 构造一个新的队列(Map),与原队列的每个元素作为方法的参数,方法调用结果作为新队列元素逐个插入.
对于QueueNode
类,实现了:
- 模板类型的元素值;
- 指向下一个节点的指针.
"-inl" 表明这是个声明和实现的混合文件.
sample3-inl.h
#include <stddef.h>
// Queue is a simple queue implemented as a singled-linked list.
//
// The element type must support copy constructor.
template <typename E> // E is the element type
class Queue;
// QueueNode is a node in a Queue, which consists of an element of
// type E and a pointer to the next node.
template <typename E> // E is the element type
class QueueNode {
friend class Queue<E>;
public:
// Gets the element in this node.
const E& element() const { return element_; }
// Gets the next node in the queue.
QueueNode* next() { return next_; }
const QueueNode* next() const { return next_; }
private:
// Creates a node with a given element value. The next pointer is
// set to NULL.
explicit QueueNode(const E& an_element)
: element_(an_element), next_(nullptr) {}
// We disable the default assignment operator and copy c'tor.
const QueueNode& operator=(const QueueNode&);
QueueNode(const QueueNode&);
E element_;
QueueNode* next_;
};
template <typename E> // E is the element type.
class Queue {
public:
// Creates an empty queue.
Queue() : head_(nullptr), last_(nullptr), size_(0) {}
// D'tor. Clears the queue.
~Queue() { Clear(); }
// Clears the queue.
void Clear() {
if (size_ > 0) {
// 1. Deletes every node.
QueueNode<E>* node = head_;
QueueNode<E>* next = node->next();
for (;;) {
delete node;
node = next;
if (node == nullptr) break;
next = node->next();
}
// 2. Resets the member variables.
head_ = last_ = nullptr;
size_ = 0;
}
}
// Gets the number of elements.
size_t Size() const { return size_; }
// Gets the first element of the queue, or NULL if the queue is empty.
QueueNode<E>* Head() { return head_; }
const QueueNode<E>* Head() const { return head_; }
// Gets the last element of the queue, or NULL if the queue is empty.
QueueNode<E>* Last() { return last_; }
const QueueNode<E>* Last() const { return last_; }
// Adds an element to the end of the queue. A copy of the element is
// created using the copy constructor, and then stored in the queue.
// Changes made to the element in the queue doesn't affect the source
// object, and vice versa.
void Enqueue(const E& element) {
QueueNode<E>* new_node = new QueueNode<E>(element);
if (size_ == 0) {
head_ = last_ = new_node;
size_ = 1;
} else {
last_->next_ = new_node;
last_ = new_node;
size_++;
}
}
// Removes the head of the queue and returns it. Returns NULL if
// the queue is empty.
E* Dequeue() {
if (size_ == 0) {
return nullptr;
}
const QueueNode<E>* const old_head = head_;
head_ = head_->next_;
size_--;
if (size_ == 0) {
last_ = nullptr;
}
E* element = new E(old_head->element());
delete old_head;
return element;
}
// Applies a function/functor on each element of the queue, and
// returns the result in a new queue. The original queue is not
// affected.
template <typename F>
Queue* Map(F function) const {
Queue* new_queue = new Queue();
for (const QueueNode<E>* node = head_; node != nullptr;
node = node->next_) {
new_queue->Enqueue(function(node->element()));
}
return new_queue;
}
private:
QueueNode<E>* head_; // The first node of the queue.
QueueNode<E>* last_; // The last node of the queue.
size_t size_; // The number of elements in the queue.
// We disallow copying a queue.
Queue(const Queue&);
const Queue& operator=(const Queue&);
};
测试文件
sample3_unittest.cc
#include "sample3-inl.h"
#include "gtest/gtest.h"
namespace {
// To use a test fixture, derive a class from testing::Test.
class QueueTestSmpl3 : public testing::Test {
protected: // You should make the members protected s.t. they can be
// accessed from sub-classes.
// virtual void SetUp() will be called before each test is run. You
// should define it if you need to initialize the variables.
// Otherwise, this can be skipped.
void SetUp() override {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() will be called after each test is run.
// You should define it if there is cleanup work to do. Otherwise,
// you don't have to provide it.
//
// virtual void TearDown() {
// }
// A helper function that some test uses.
static int Double(int n) { return 2 * n; }
// A helper function for testing Queue::Map().
void MapTester(const Queue<int>* q) {
// Creates a new queue, where each element is twice as big as the
// corresponding one in q.
const Queue<int>* const new_q = q->Map(Double);
// Verifies that the new queue has the same size as q.
ASSERT_EQ(q->Size(), new_q->Size());
// Verifies the relationship between the elements of the two queues.
for (const QueueNode<int>*n1 = q->Head(), *n2 = new_q->Head();
n1 != nullptr; n1 = n1->next(), n2 = n2->next()) {
EXPECT_EQ(2 * n1->element(), n2->element());
}
delete new_q;
}
// Declares the variables your tests want to use.
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
// When you have a test fixture, you define a test using TEST_F
// instead of TEST.
// Tests the default c'tor.
TEST_F(QueueTestSmpl3, DefaultConstructor) {
// You can access data in the test fixture here.
EXPECT_EQ(0u, q0_.Size());
}
// Tests Dequeue().
TEST_F(QueueTestSmpl3, Dequeue) {
int* n = q0_.Dequeue();
EXPECT_TRUE(n == nullptr);
n = q1_.Dequeue();
ASSERT_TRUE(n != nullptr);
EXPECT_EQ(1, *n);
EXPECT_EQ(0u, q1_.Size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != nullptr);
EXPECT_EQ(2, *n);
EXPECT_EQ(1u, q2_.Size());
delete n;
}
// Tests the Queue::Map() function.
TEST_F(QueueTestSmpl3, Map) {
MapTester(&q0_);
MapTester(&q1_);
MapTester(&q2_);
}
} // namespace
sample3的测试并没有像sample2那样,在测试用例中定义测试对象,然后进行一系列操作后再断言测试,而是用了一个继承自testing::Test
的测试夹具类QueueTestSmpl3
,包装了对测试对象的一系列操作,后续测试不需要重复编写.
TEST_IF
:用测试夹具测试时,定义测试用例不用TEST
,而是用TEST_IF
.
ASSERT_TRUE
:功能类似EXPECT_TRUE
,但断言不通过时,前者会导致测试不会继续,后者会继续.
对于QueueTestSmpl3
类,
- 定义了3个待测的
Queue<int>
对象q0_, q1_, q2_
,并用父类testing::Test
的派生方法进行初始化; - Setup():派生自testing::Test,会在执行测试用例之前运行. 如果有数据初始化工作,可以在这里进行;
- MapTester():包装对
Queue::Map()
的测试操作.
对于Queue
和QueueNode
,并没有对每个public方法设计测试用例,而是让测试用例覆盖其成员方法.
- DefaultConstructor:测试默认构造函数,包含了ctor和Enqueue();
- Dequeue:测试出队列方法;
- Map:利用测试夹具中定义的MapTester方法,对Queue::Map进行测试.
当然,这里其实没有覆盖对Queue::Clear()
方法的测试.
小结
利用测试夹具类(继承自testing::test)封装对待测类对象的初始化,可自定义测试方法 封装对待测对象的一系列操作.
本文作者:明明1109
本文链接:https://www.cnblogs.com/fortunely/p/18741407
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2022-02-27 muduo笔记 线程安全相关类MutexLock, MutexLockGuard
2022-02-27 muduo笔记 标记类copyable, noncopyable
2022-02-27 muduo笔记 原子类AtomicIntegerT<T>
2022-02-27 muduo笔记 时间戳类Timestamp