2025-02-27 18:24阅读: 3评论: 0推荐: 0

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()的测试操作.

对于QueueQueueNode,并没有对每个public方法设计测试用例,而是让测试用例覆盖其成员方法.

  • DefaultConstructor:测试默认构造函数,包含了ctor和Enqueue();
  • Dequeue:测试出队列方法;
  • Map:利用测试夹具中定义的MapTester方法,对Queue::Map进行测试.

当然,这里其实没有覆盖对Queue::Clear()方法的测试.

小结

利用测试夹具类(继承自testing::test)封装对待测类对象的初始化,可自定义测试方法 封装对待测对象的一系列操作.

本文作者:明明1109

本文链接:https://www.cnblogs.com/fortunely/p/18741407

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   明明1109  阅读(3)  评论(0编辑  收藏  举报
历史上的今天:
2022-02-27 muduo笔记 线程安全相关类MutexLock, MutexLockGuard
2022-02-27 muduo笔记 标记类copyable, noncopyable
2022-02-27 muduo笔记 原子类AtomicIntegerT<T>
2022-02-27 muduo笔记 时间戳类Timestamp
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.