cppunit,这是一个与JUnit类似的框架,这个框架很陈旧了,并且有着一些缺点,例如一些类可以消失,一些类名应该修改,一些宏定义应该修改,帮助很少很乱等,这里就不再一一赘述,感兴趣的同学可以百度一下。因为cppunit有着一系列的缺点,cppunit的鼻祖之一重写了一套C/C++单元测试框架,这就是cxxtest。与cppunit相比,可以说cxxtest具有如下一些优点:不需要RTTI(运行时间类型信息);不需要成员模板功能;不需要异常处理;不需要任何外部函数库(包括内存管理、文件/控制台的输入/输出和图形库等);它完全是作为一套头文件的集合而进行发布的。另外由于由于cppunit带有Make文件, 所以只能用在主要的 *** 作系统中,而应用到不常见 *** 作系统中源代码及Make文件修改的工作量就会很大。cxxtest不带Make文件, 所以也可用于其他 *** 作系统中,具有更好的可移植性和可用性。Gtest虽然也使用Makefile文件,但是通过libtool动态加载来实现,可以支持Supports Linux, Windows, Mac OS, 以及其他 *** 作系统。
1.2. cxxtestcxxtest也有一些缺点,例如需要用到perl或者python对测试代码的头文件进行文法扫描,生成可执行代码,准备工作比较麻烦。并且cxxtest的绝大多数功能都可以使用gtest来完成,所以一般情况下就更加推荐gtest,一步到位。在百度ATP的自动化测试工具推荐名单中,gtest也是作为一个推荐的工具来给出的,并且指出了cxxtest的使用可以转为用gtest代替。下面先给大家列出一些cxxtest和gtest之间的比较,这样大家就有个直观的印象。
1.3. GTestgtest是一个跨平台(Liunx、Mac OS X、Windows、Cygwin、Windows CE and Symbian)的C++测试框架,有google公司发布。gtest测试框架是在不同平台上为编写C++测试而生成的。
这是Google的开源C++单元测试框架,是遵循 New BSD License (可用作商业用途)的开源项目。据说google内部的大多数C++代码都已经使用这个测试框架进行单测,gtest 可以支持绝大多数大家所熟知的平台。Gtest的使用较为方便,与 CppUnit 不同的是,gtest 可以自动记录下所有定义好的测试,不需要用户通过列举来指明哪些测试需要运行。
2. 安装GTest下载源码
git clone https://github.com/google/googletest3. 使用GTest 3.1. 代码
gtest_test.cpp文件
注意:如果有命令空间,main函数要放到命名空间外面
#include "gtest/gtest.h" #include "fun.h" TEST(fun, add) { EXPECT_EQ(1, add(2,-1)); EXPECT_EQ(5, add(2,3)); } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
fun.h文件
#ifndef _FUN_H_ #define _FUN_H_ #include3.2. 编译#include // Returns n! (the factorial of n). For negative n, n! is defined to be 1. int Factorial(int n); // Returns true if n is a prime number. bool IsPrime(int n); // A simple string class. class MyString { private: const char* c_string_; const MyString& operator=(const MyString& rhs); public: // Clones a 0-terminated C string, allocating memory using new. static const char* CloneCString(const char* a_c_string); // C'tors // The default c'tor constructs a NULL string. MyString() : c_string_(NULL) {} // Constructs a MyString by cloning a 0-terminated C string. explicit MyString(const char* a_c_string) : c_string_(NULL) { Set(a_c_string); } // Copy c'tor MyString(const MyString& string) : c_string_(NULL) { Set(string.c_string_); } // D'tor. MyString is intended to be a final class, so the d'tor // doesn't need to be virtual. ~MyString() { delete[] c_string_; } // Gets the 0-terminated C string this MyString object represents. const char* c_string() const { return c_string_; } size_t Length() const { return c_string_ == NULL ? 0 : strlen(c_string_); } // Sets the 0-terminated C string this MyString object represents. void Set(const char* c_string); }; // Queue is a simple queue implemented as a singled-linked list. // // The element type must support copy constructor. template // 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 // E is the element type class QueueNode { friend class Queue ; 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_(NULL) {} // We disable the default assignment operator and copy c'tor. const QueueNode& operator = (const QueueNode&); QueueNode(const QueueNode&); E element_; QueueNode* next_; }; template // E is the element type. class Queue { public: // Creates an empty queue. Queue() : head_(NULL), last_(NULL), size_(0) {} // D'tor. Clears the queue. ~Queue() { Clear(); } // Clears the queue. void Clear() { if (size_ > 0) { // 1. Deletes every node. QueueNode * node = head_; QueueNode * next = node->next(); for (; ;) { delete node; node = next; if (node == NULL) break; next = node->next(); } // 2. Resets the member variables. head_ = last_ = NULL; 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 * Head() { return head_; } const QueueNode * Head() const { return head_; } // Gets the last element of the queue, or NULL if the queue is empty. QueueNode * Last() { return last_; } const QueueNode * 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 * new_node = new QueueNode (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 NULL; } const QueueNode * const old_head = head_; head_ = head_->next_; size_--; if (size_ == 0) { last_ = NULL; } 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 Queue* Map(F function) const { Queue* new_queue = new Queue(); for (const QueueNode * node = head_; node != NULL; node = node->next_) { new_queue->Enqueue(function(node->element())); } return new_queue; } private: QueueNode * head_; // The first node of the queue. QueueNode * 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&); }; // A simple monotonic counter. class Counter { private: int counter_; public: // Creates a counter that starts at 0. Counter() : counter_(0) {} // Returns the current counter value, and increments it. int Increment(); // Prints the current counter value to STDOUT. void Print() const; }; // The prime table interface. class Primetable { public: virtual ~Primetable() {} // Returns true iff n is a prime number. virtual bool IsPrime(int n) const = 0; // Returns the smallest prime number greater than p; or returns -1 // if the next prime is beyond the capacity of the table. virtual int GetNextPrime(int p) const = 0; }; // Implementation #1 calculates the primes on-the-fly. class onTheFlyPrimetable : public Primetable { public: virtual bool IsPrime(int n) const { if (n <= 1) return false; for (int i = 2; i*i <= n; i++) { // n is divisible by an integer other than 1 and itself. if ((n % i) == 0) return false; } return true; } virtual int GetNextPrime(int p) const { for (int n = p + 1; n > 0; n++) { if (IsPrime(n)) return n; } return -1; } }; // Implementation #2 pre-calculates the primes and stores the result // in an array. class PreCalculatedPrimetable : public Primetable { public: // 'max' specifies the maximum number the prime table holds. explicit PreCalculatedPrimetable(int max) : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) { CalculatePrimesUpTo(max); } virtual ~PreCalculatedPrimetable() { delete[] is_prime_; } virtual bool IsPrime(int n) const { return 0 <= n && n < is_prime_size_ && is_prime_[n]; } virtual int GetNextPrime(int p) const { for (int n = p + 1; n < is_prime_size_; n++) { if (is_prime_[n]) return n; } return -1; } private: void CalculatePrimesUpTo(int max) { ::std::fill(is_prime_, is_prime_ + is_prime_size_, true); is_prime_[0] = is_prime_[1] = false; for (int i = 2; i <= max; i++) { if (!is_prime_[i]) continue; // Marks all multiples of i (except i itself) as non-prime. for (int j = 2*i; j <= max; j += i) { is_prime_[j] = false; } } } const int is_prime_size_; bool* const is_prime_; // Disables compiler warning "assignment operator could not be generated." void operator=(const PreCalculatedPrimetable& rhs); }; #endif//_FUN_H_
如果test中写了main函数,则编译比较简单;如果test中没有写main函数,则编译时需要链接gtest_main
3.3. 运行make test CTEST_OUTPUT_ON_FAILURE=TRUE GTEST_COLOR=TRUE4. GTest的一些基本概念
要测试一个类或函数,我们需要对其行为做出断言。当一个断言失败时,Google Test会在屏幕上输出该代码所在的源文件及其所在的位置行号,以及错误信息。也可以在编写断言时,提供一个自定义的错误信息,这个信息在失败时会被附加在Google Test的错误信息之后。
断言常常成对出现,它们都测试同一个类或者函数,但对当前功能有着不同的效果。ASSERT_*版本的断言失败时会产生致命失败,并结束当前函数。EXPECT_*版本的断言产生非致命失败,而不会中止当前函数。通常更推荐使用EXPECT_*断言,因为它们运行一个测试中可以有不止一个的错误被报告出来。但如果在编写断言如果失败,就没有必要继续往下执行的测试时,你应该使用ASSERT_*断言。 因为失败的ASSERT_*断言会立刻从当前的函数返回,可能会跳过其后的一些的清洁代码,这样也许会导致空间泄漏。
5. GTest的断言 5.1. 布尔值检查Fatal assertion
Nonfatal assertion
Verifies
ASSERT_TRUE(condition);
EXPECT_TRUE(condition);
condition is true
ASSERT_FALSE(condition);
EXPECT_FALSE(condition);
condition is false
Fatal assertion
Nonfatal assertion
Verifies
ASSERT_EQ(expected, actual);
EXPECT_EQ(expected, actual);
expected == actual
ASSERT_NE(val1, val2);
EXPECT_NE(val1, val2);
val1 != val2
ASSERT_LT(val1, val2);
EXPECT_LT(val1, val2);
val1 < val2
ASSERT_LE(val1, val2);
EXPECT_LE(val1, val2);
val1 <= val2
ASSERT_GT(val1, val2);
EXPECT_GT(val1, val2);
val1 > val2
ASSERT_GE(val1, val2);
EXPECT_GE(val1, val2);
val1 >= val2
Fatal assertion
Nonfatal assertion
Verifies
ASSERT_STREQ(expected_str, actual_str);
EXPECT_STREQ(expected_str, actual_str);
两个C字符串有相同的内容
ASSERT_STRNE(str1, str2);
EXPECT_STRNE(str1, str2);
两个C字符串有不同的内容
ASSERT_STRCASEEQ(expected_str, actual_str);
EXPECT_STRCASEEQ(expected_str, actual_str);
两个C字符串有相同的内容,忽略大小写
ASSERT_STRCASENE(str1, str2);
EXPECT_STRCASENE(str1, str2);
两个C字符串有不同的内容,忽略大小写
Fatal assertion
Nonfatal assertion
Verifies
ASSERT_THROW(statement, exception_type);
EXPECT_THROW(statement, exception_type);
statement throws an exception of the given type
ASSERT_ANY_THROW(statement);
EXPECT_ANY_THROW(statement);
statement throws an exception of any type
ASSERT_NO_THROW(statement);
EXPECT_NO_THROW(statement);
statement doesn't throw any exception
Fatal assertion
Nonfatal assertion
Verifies
ASSERT_FLOAT_EQ(expected, actual);
EXPECT_FLOAT_EQ(expected, actual);
the two float values are almost equal
ASSERT_DOUBLE_EQ(expected, actual);
EXPECT_DOUBLE_EQ(expected, actual);
the two double values are almost equal
对相近的两个数比较:
Fatal assertion
Nonfatal assertion
Verifies
ASSERT_NEAR(val1, val2, abs_error);
EXPECT_NEAR(val1, val2, abs_error);
the difference between val1 and val2 doesn't exceed the given absolute error
很多工程都包含UT文件,当这个工程编译链接库时,注意要把UT文件从链接库中剔除,然后单独把UT文件编成可执行文件。
参考文献- gtest简介及简单使用_网络资源是无限的-CSDN博客_gtest
- gtest框架的介绍与应用_踏雪无痕-CSDN博客
- GTest的安装与使用 - 晓乎 - 博客园
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)