gtest基础使用08:Google Test自带示例五:Test Fixture的基类和子类

一、环境信息

  1. Visual Studio 2019
  2. Windows 10
  3. 前导知识:Google Test Sample01的学习总结Google Test Sample03的学习总结

二、Google Test Sample05

1. 示例概述

1.1 sample05在01、03两个示例的基础上展示了如何继承Test Fixture,对已有的Test Fixture进行继承,往往发生在如下两个场景 (1) 定义的Test Fixture可用于指定的一套单元测试用例集,当有多套测试用例时,如何处理?(2) 当不同的测试用例集对应的测试资源基本相同、但又存在差异,又如何处理?
1.2 被继承的Test Fixture在Google Test 中被称为 Super Fixture、继承者被称为sub fixture。Super Fixture /Test Fixture 本质就是一个类,类当然可以被继承
1.3 sample05需要用到 sample01.h + sample01.cpp, sample03.h,文件结构如下
在这里插入图片描述
1.4 sample01.cpp 包含Factorial() 、IsPrime()两个函数的具体实现

#include "sample01.h"

// Returns n! (the factorial of n).  For negative n and zero, n! is defined to be 1.
int Factorial(int n) 
{
    int result = 1;

    for (int i = 1; i <= n; i++) 
    {
        result *= i;
    }

    return result;
}

// Returns true if and only if n is a prime number.
bool IsPrime(int n) //素数定义: 在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数
{
    // Trivial case 1: small numbers
    if (n <= 1) return false;

    // Trivial case 2: even numbers
    if (n % 2 == 0) return n == 2; //目前不清楚实现原理,当n=2 返回True;当n=4 6.., 返回False 
    //if (n % 2 == 0) return false; //wrong code 

    // Now, we have that n is odd and n >= 3.
    // Try to divide n by every odd number i, starting from 3
    for (int i = 3; ; i += 2)
    {
        // We only have to try i up to the square root of n
        if (i > n / i) break;

        // Now, we have i <= n/i < n.
        // If n is divisible by i, n is not prime.
        if (n % i == 0) return false;
    }

    // n has no integer factor in the range (1, n), and thus is prime.
    return true;
}

1.5 sample01.h 对Factorial(), IsPrime()函数进行了声明

#ifndef  sample_01
#define sample_01

// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n);

// Returns true if and only if n is a prime number.
bool IsPrime(int n);

#endif // ! sample_01

1.6 sample03.h 完整定义了类Queue(包含成员函数的具体实现)

#ifndef GOOGLETEST_SAMPLES_SAMPLE3_INL_H_
#define GOOGLETEST_SAMPLES_SAMPLE3_INL_H_

//#include <stddef.h>
//using namespace std;

// Queue is a simple queue implemented as a singled-linked list.
// The element type must support copy constructor.
template <typename E> class Queue; // E is the element type

// 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> class QueueNode // QueueNode是一个队列中的结点,结点中包含 类型为E的元素 和 指向下一个结点的指针
{
	friend class Queue<E>; //Queue是QueueNode的友元类,可以访问QueueNode的所有成员

	private:
		E element_;
		QueueNode* next_; //指向类的指针,是自己少见多怪吧

		// 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) {} //构造函数 //explicit? 

		// We disable the default assignment operator and copy c'tor. //why disable?
		const QueueNode& operator= (const QueueNode&);
		QueueNode(const QueueNode&);

	public:
		const E &element() const // Gets the element in this node. 返回结点的元素值(类型E的一个引用)
		{
			return element_;
		}

		QueueNode* next() //Gets the next node in the queue.
		{
			return next_;
		}
		const QueueNode* next() const  //为什么出现两个几乎完全一样的 next()呢?
		{
			return next_;
		}
};

template <typename E>  // E is the element type.
class 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. //size_t almost equal to int 

		// We disallow copying a queue. //why disallow?
		Queue(const Queue&);
		const Queue& operator = (const Queue&);

	public:
		Queue() : head_(nullptr), last_(nullptr), size_(0) {} // Creates an empty queue.

		~Queue() { Clear(); } //D'tor. Clears the queue.  //析构函数,用于清除队列

		void Clear() // Clears the queue.
		{
			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;
			}
		}

		size_t Size() const { return size_; } // Gets the number of elements.

		// 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_; } //为什么写两个 Head()? const?

		// 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.  //vice versa means '反之亦然'
		void Enqueue(const E &element) //向队列添加元素,不会影响源数据
		{
			QueueNode<E>* new_node = new QueueNode<E>(element); //Apply for memory through 'new'
			// explicit QueueNode(const E &an_element):element_(an_element), next_(nullptr) {} 
			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() ) ); //直接void Enqueue(const E &element); 就可以了吧,function多此一举吧?
				//不是多此一举,在 sample03UnitTest.cpp中就可以看到function()的巧妙使用
			}

			return new_queue;
		}

};

#endif  // GOOGLETEST_SAMPLES_SAMPLE3_INL_H_

2. 对应的单元测试用例

2.1 sample05中定义了名为QuickTest的Test Fixture,用来判定用例的执行时间是否超过5秒

class QuickTest : public testing::Test 
    {//用例从SetUp()调用时启动执行,从TearDown()调用时结束执行,因此期间的时间就是用例执行时间
    protected:
        time_t start_time_;
        void SetUp() override
         { 
        	start_time_ = time(nullptr); 
        }
        void TearDown() override
        { 
        	const time_t end_time = time(nullptr);
            EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long.";
        }
    };

2.2 IntegerFunctionTest继承自Test Fixture QuickTest :解决了文章开头的问题1

class IntegerFunctionTest : public QuickTest{ }TEST_F(IntegerFunctionTest, Factorial)
 {
        EXPECT_EQ(1, Factorial(-5)); //每条用例都会判定是否超过5秒
        EXPECT_EQ(1, Factorial(-1));
 }

2.3 QueueTest也继承自Test Fixture QuickTest,但进行了必要的差异化:解决了文章开头的问题2

class QueueTest : public QuickTest
    {
    protected:
        void SetUp() override
        {
            // First, we need to set up the super fixture (QuickTest).
            QuickTest::SetUp();

            // Second, some additional setup for this fixture. //差异化
            q1_.Enqueue(1);
            q2_.Enqueue(2);
            q2_.Enqueue(3);
        }
        // 没有数据需要清理,因此TearDown()不进行重新定义、直接继承即可
        // virtual void TearDown() {QuickTest::TearDown(); }
        
        Queue<int> q0_; //差异化
        Queue<int> q1_;
        Queue<int> q2_;
    };

2.4 使用QueueTest的TEST_F,由于继承自QuickTest,同样会判定用例的执行是否超过5秒

TEST_F(QueueTest, DefaultConstructor)
    {
        EXPECT_EQ(0, q0_.Size());
    }

2.5 最后,Google也提到了QueueTest, IntegerFunctionTest 也可以被继承,即:可以进行Test Fixture继承的继承,这种继承没有层数限制
2.6 单元测试用例源码及注释

#include "pch.h"
// This sample teaches how to reuse a test fixture in multiple test
// cases by deriving sub-fixtures from it.
//
// When you define a test fixture, you specify the name of the test
// case that will use this fixture.  Therefore, a test fixture can
// be used by only one test case.
//
// Sometimes, more than one test cases may want to use the same or
// slightly different test fixtures.  For example, you may want to
// make sure that all tests for a GUI library don't leak important
// system resources like fonts and brushes.  In Google Test, you do
// this by putting the shared logic in a super (as in "super class")
// test fixture, and then have each test case use a fixture derived
// from this super fixture.
// 
// Test Fixture可用于TEST_F宏,但是测试用例集的名称必须与TestFixture名称一致,但有多套测试用例时,如何处理?
// 当不同的测试用例集对应的测试资源基本相同时,又如何处理?

#include <limits.h>
#include <time.h>
//#include "gtest/gtest.h"
#include "sample01.h"
#include "sample03.h"
namespace {
    // In this sample, we want to ensure that every test finishes within
    // ~5 seconds.  If a test takes longer to run, we consider it a
    // failure.
    //在5秒钟未完成的测试项,就会被判定为Fail
    // 
    // We put the code for timing a test in a test fixture called
    // "QuickTest".  QuickTest is intended to be the super fixture that
    // other fixtures derive from, therefore there is no test case with
    // the name "QuickTest".  This is OK.
    // QuickTest是super fixture,其他的test fixture可以继承QuickTest
    // 
    // Later, we will derive multiple test fixtures from QuickTest.
    class QuickTest : public testing::Test 
    {
    protected:
        // The UTC time (in seconds) when the test starts
        time_t start_time_;

        // Remember that SetUp() is run immediately before a test starts.
        // 测试启动时,SetUp()就会执行,因此SetUp()的执行时间作为启动时间
        // This is a good place to record the start time.
        void SetUp() override
        { 
            start_time_ = time(nullptr); 
        }

        // TearDown() is invoked immediately after a test finishes.  Here we
        // check if the test was too slow.
        void TearDown() override 
        {
            const time_t end_time = time(nullptr);// Gets the time when the test finishes

            // Asserts that the test took no more than ~5 seconds.  
            // Did you know that you can use assertions in SetUp() and TearDown() as well? //秀啊
            EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long.";
        }
    };


    // We derive a fixture named IntegerFunctionTest from the QuickTest fixture.
    // All tests using this fixture will be automatically required to be quick. 
    // Test Fixture的继承
    class IntegerFunctionTest : public QuickTest 
    {
        // We don't need any more logic than already in the QuickTest fixture.
        // Therefore the body is empty.
    };


    // Now we can write tests in the IntegerFunctionTest test case.

    // Tests Factorial()
    TEST_F(IntegerFunctionTest, Factorial) {
        // Tests factorial of negative numbers.
        EXPECT_EQ(1, Factorial(-5));
        EXPECT_EQ(1, Factorial(-1));
        EXPECT_GT(Factorial(-10), 0);

        // Tests factorial of 0.
        EXPECT_EQ(1, Factorial(0));

        // Tests factorial of positive numbers.
        EXPECT_EQ(1, Factorial(1));
        EXPECT_EQ(2, Factorial(2));
        EXPECT_EQ(6, Factorial(3));
        EXPECT_EQ(40320, Factorial(8));
    }


    // Tests IsPrime()
    TEST_F(IntegerFunctionTest, IsPrime)
    {
        // Tests negative input.
        EXPECT_FALSE(IsPrime(-1));
        EXPECT_FALSE(IsPrime(-2));
        EXPECT_FALSE(IsPrime(INT_MIN)); //INT_MIN是边界值

        // Tests some trivial cases.
        EXPECT_FALSE(IsPrime(0));
        EXPECT_FALSE(IsPrime(1));
        EXPECT_TRUE(IsPrime(2));
        EXPECT_TRUE(IsPrime(3));

        // Tests positive input.
        EXPECT_FALSE(IsPrime(4));
        EXPECT_TRUE(IsPrime(5));
        EXPECT_FALSE(IsPrime(6));
        EXPECT_TRUE(IsPrime(23));
    }


    // The next test case (named "QueueTest") also needs to be quick, so
    // we derive another fixture from QuickTest.
    // 同样继承自QuickTest,但是新创建的Test Fixture需要进行一定的定制化
    // 
    // The QueueTest test fixture has some logic and shared objects in
    // addition to what's in QuickTest already.  We define the additional
    // stuff inside the body of the test fixture, as usual.
    class QueueTest : public QuickTest
    {
    protected:
        void SetUp() override
        {
            // First, we need to set up the super fixture (QuickTest).
            QuickTest::SetUp();

            // Second, some additional setup for this fixture.
            q1_.Enqueue(1);
            q2_.Enqueue(2);
            q2_.Enqueue(3);
        }

        // By default, TearDown() inherits the behavior of
        // QuickTest::TearDown().  As we have no additional cleaning work
        // for QueueTest, we omit it here.
        // 没有数据需要清理,因此TearDown()不进行重新定义、直接继承即可
        // virtual void TearDown() {QuickTest::TearDown(); }

        Queue<int> q0_;
        Queue<int> q1_;
        Queue<int> q2_;
    };


    // Now, let's write tests using the QueueTest fixture.

    // Tests the default constructor.
    TEST_F(QueueTest, DefaultConstructor)
    {
        EXPECT_EQ(0, q0_.Size());
    }

    // Tests Dequeue().
    TEST_F(QueueTest, Dequeue) 
    {
        int* n = q0_.Dequeue();
        EXPECT_TRUE(n == nullptr);

        n = q1_.Dequeue();
        EXPECT_TRUE(n != nullptr);
        EXPECT_EQ(1, *n);
        EXPECT_EQ(0u, q1_.Size());
        delete n;

        n = q2_.Dequeue();
        EXPECT_TRUE(n != nullptr);
        EXPECT_EQ(2, *n);
        EXPECT_EQ(1u, q2_.Size());
        delete n;
    }
}  // namespace
// If necessary, you can derive further test fixtures from a derived
// fixture itself.  For example, you can derive another fixture from
// QueueTest.  Google Test imposes no limit on how deep the hierarchy
// can be.  In practice, however, you probably don't want it to be too
// deep as to be confusing. //可以进行Test Fixture子继承的继承

2.7 运行结果
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值