【收藏】MyBatis 常用語法匯總
898
2022-05-30
1??????引言
當你開始開發(fā)新的庫/類/程序時,你需要做的第一件事是什么?
沒錯。你需要從單元測試模塊開始。
現(xiàn)在我們來看看C++?白盒測試比較流行的單元測試框架。
2??????Boost.Test
Boost.Test是一個C++03/11/14/17單元測試庫,可用于多種平臺和編譯器。
該庫是Boost的一部分。該庫的最新版本可以從boost網(wǎng)站上獲得。
該庫的完整使用說明可以從http://www.boost.org/doc/libs/release/libs/test/。
2.1????官方網(wǎng)站
http://www.boost.org
https://github.com/boostorg/test
2.2????許可
Boost Software License - Version 1.0
2.3????主要特點及使用方法
l??容易上手:
n??下載并使用boost庫
n??用下面兩行創(chuàng)建一個測試模塊:
#define?BOOST_TEST_MODULE?your_test_module
#include?
n??編寫一個測試案例:
BOOST_AUTO_TEST_CASE(?your_test_case?)?{
std::vector
std::vector
BOOST_TEST(?a?==?b?);
}
n??編譯運行
l??強大而獨特的測試斷言宏BOOST_TEST,可用來檢測浮點數(shù)、集合、字符串......并支持適當?shù)谋容^范式。
l??自注冊測試用例,在測試套件中組織用例,在測試用例、套件或全局上應用Fixture。
l??為故障的高級診斷提供斷言。
l??強大且可擴展的數(shù)據(jù)集測試。
l??可為測試用例和套件添加高級描述、組/標簽和依賴關系的裝飾。
l??強大的命令行選項和測試案例過濾器。
l??為第三方工具提供可擴展的日志記錄、XML和JUNIT輸出(例如:連續(xù)集成)。
l??各種方法(如共享/靜態(tài)庫/頭)用以加快集成和/或編譯/構建周期,生成更小的二進制文件。
2.4????用法
2.4.1????簡單測試
看一下簡單的測試用例。
#include?
#define?BOOST_TEST_MODULE?MyTest
#include?
BOOST_AUTO_TEST_CASE(?my_test?)
{
my_class?test_object(?"qwerty"?);
BOOST_CHECK(?test_object.is_valid()?);
}
#define?BOOST_TEST_MODULE?MyTest
#include?
int?add(?int?i,?int?j?)?{?return?i+j;?}
BOOST_AUTO_TEST_CASE(?my_test?)
{
//?七種方法來檢測和報告相同的錯誤:
BOOST_CHECK(?add(?2,2?)?==?4?);????????//?#1?出錯后繼續(xù)
BOOST_REQUIRE(?add(?2,2?)?==?4?);??????//?#2?出錯后拋出
if(?add(?2,2?)?!=?4?)
BOOST_ERROR(?"Ouch..."?);????????????//?#3?出錯后繼續(xù)
if(?add(?2,2?)?!=?4?)
BOOST_FAIL(?"Ouch..."?);?????????????//?#4?出錯后拋出
if(?add(?2,2?)?!=?4?)?throw?"Ouch...";?//?#5?出錯后拋出
BOOST_CHECK_MESSAGE(?add(?2,2?)?==?4,??//?#6?出錯后繼續(xù)
"add(..)?result:?"?<
BOOST_CHECK_EQUAL(?add(?2,2?),?4?);???//?#7?出錯后繼續(xù)
}
2.4.2????Fixture
看一下測試用例Fixture。
Fixture設置在測試用例執(zhí)行前被調(diào)用,F(xiàn)ixture拆除在測試用例完成執(zhí)行后被調(diào)用,與測試用例的執(zhí)行狀態(tài)無關。
#define?BOOST_TEST_MODULE?example
#include?
struct?F?{
F()?:?i(?0?)?{?BOOST_TEST_MESSAGE(?"setup?fixture"?);?}
~F()?????????{?BOOST_TEST_MESSAGE(?"teardown?fixture"?);?}
int?i;
};
BOOST_FIXTURE_TEST_CASE(?test_case1,?F?)
{
BOOST_TEST(?i?==?1?);
++i;
}
BOOST_FIXTURE_TEST_CASE(?test_case2,?F?)
{
BOOST_CHECK_EQUAL(?i,?1?);
}
BOOST_AUTO_TEST_CASE(?test_case3?)
{
BOOST_TEST(?true?);
}
2.4.3????Suite
在測試套件開始和結束聲明之間定義的測試單元成為測試Suite的成員。一個測試單元總是成為最近的測試Suite的成員。在測試文件范圍內(nèi)聲明的測試單元會成為主測試Suite的成員。測試Suite包含的深度沒有限制。
#define?BOOST_TEST_MODULE?example
#include?
BOOST_AUTO_TEST_SUITE(?test_suite1?)
BOOST_AUTO_TEST_CASE(?test_case1?)
{
BOOST_WARN(?sizeof(int)?4?);
}
BOOST_AUTO_TEST_CASE(?test_case2?)
{
BOOST_REQUIRE_EQUAL(?1,?2?);
BOOST_FAIL(?"Should?never?reach?this?line"?);
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(?test_suite2?)
BOOST_AUTO_TEST_CASE(?test_case3?)
{
BOOST_CHECK(?true?);
}
BOOST_AUTO_TEST_CASE(?test_case4?)
{
BOOST_CHECK(?false?);
}
BOOST_AUTO_TEST_SUITE_END()
3??????cppunit
CppUnit是著名的JUnit框架的C++移植,用于單元測試。
測試輸出為XML或文本格式,用于自動測試。
3.1????官方網(wǎng)站
http://cppunit.sourceforge.net/
3.2????許可
GNU Library or Lesser General Public License version 2.0 (LGPLv2)
3.3????用法
3.3.1????簡單的測試
派生TestCase類。重寫方法runTest()。當你想檢查一個值時,調(diào)用CPPUNIT_ASSERT(bool),并傳入一個表達式。
如果測試成功則為真。
class?ComplexNumberTest?:?public?CppUnit::TestCase?{
public:
ComplexNumberTest(?std::string?name?)?:?CppUnit::TestCase(?name?)?{}
void?runTest()?{
CPPUNIT_ASSERT(?Complex?(10,?1)?==?Complex?(10,?1)?);
CPPUNIT_ASSERT(?!(Complex?(1,?1)?==?Complex?(2,?2))?);
}
};
3.3.2????Fixture
Fixture是一組已知的對象,作為一組測試用例的基礎。在開發(fā)過程中進行測試時,F(xiàn)ixture非常方便。
class?ComplexNumberTest?:?public?CppUnit::TestFixture?{
private:
Complex?*m_10_1,?*m_1_1,?*m_11_2;
public:
void?setUp()
{
m_10_1?=?new?Complex(?10,?1?);
m_1_1?=?new?Complex(?1,?1?);
m_11_2?=?new?Complex(?11,?2?);
}
void?tearDown()
{
delete?m_10_1;
delete?m_1_1;
delete?m_11_2;
}
};
3.3.3????測試案例
如何使用Fixture編寫和調(diào)用單個測試?
這個過程有兩個步驟:
1.?????????把測試用例寫成Fixture類的方法
2.?????????創(chuàng)建一個運行該方法的TestCaller。
class?ComplexNumberTest?:?public?CppUnit::TestFixture??{
private:
Complex?*m_10_1,?*m_1_1,?*m_11_2;
public:
void?setUp()
{
m_10_1?=?new?Complex(?10,?1?);
m_1_1?=?new?Complex(?1,?1?);
m_11_2?=?new?Complex(?11,?2?);
}
void?tearDown()
{
delete?m_10_1;
delete?m_1_1;
delete?m_11_2;
}
void?testEquality()
{
CPPUNIT_ASSERT(?*m_10_1?==?*m_10_1?);
CPPUNIT_ASSERT(?!(*m_10_1?==?*m_11_2)?);
}
void?testAddition()
{
CPPUNIT_ASSERT(?*m_10_1?+?*m_1_1?==?*m_11_2?);
}
};
可以像這樣為每個測試用例創(chuàng)建并運行實例:
CppUnit::TestCaller
&ComplexNumberTest::testEquality?);
CppUnit::TestResult?result;
test.run(?&result?);
測試調(diào)用器構造函數(shù)的第二個參數(shù)是ComplexNumberTest上一個方法的地址。當測試調(diào)用器運行時,該特定方法將被運行。
一旦你有幾個測試,就把它們組織成一個Suite。
3.3.4????Suite
CppUnit提供了一個TestSuite類,可以一起運行任意數(shù)量的TestCases。
要創(chuàng)建一個由兩個或多個測試組成的套件,請執(zhí)行以下操作:
CppUnit::TestSuite?suite;
CppUnit::TestResult?result;
suite.addTest(?new?CppUnit::TestCaller
"testEquality",
&ComplexNumberTest::testEquality?)?);
suite.addTest(?new?CppUnit::TestCaller
"testAddition",
&ComplexNumberTest::testAddition?)?);
suite.run(?&result?);
3.3.5????TestRunner
一旦你有了一個測試Suite,你就會想要運行它。CppUnit?提供了一些工具來定義要運行的Suite并顯示其結果。你可以通過一個靜態(tài)方法Suite來使你的Suite可以被TestRunner程序訪問,并返回一個測試Suite。
#include?
#include?"ExampleTestCase.h"
#include?"ComplexNumberTest.h"
int?main(?int?argc,?char?**argv)
{
CppUnit::TextUi::TestRunner?runner;
runner.addTest(?ExampleTestCase::suite()?);
runner.addTest(?ComplexNumberTest::suite()?);
runner.run();
return?0;
}
TestRunner將運行這些測試。如果所有的測試都通過了,你會得到一條信息性消息。如果有任何測試失敗,你會得到以下信息:
n??失敗的測試用例的名稱
n??包含測試的源文件的名稱。
n??發(fā)生故障的行號
n??調(diào)用CPPUNIT_ASSERT()檢測到故障的所有文本。
CppUnit可以區(qū)分失敗和錯誤。失敗是預期的,并通過斷言進行檢查。錯誤是未預料到的問題,比如零除法和其他由C++運行時或你的代碼引發(fā)的異常。
4??????GoogleTest
谷歌測試和模擬框架。
4.1????官方網(wǎng)站
https://github.com/google/googletest/
4.2????許可
BSD-3-Clause License
4.3????主要特點
n??一個xUnit測試框架。
n??測試發(fā)現(xiàn)。
n??豐富的斷言集。
n??用戶定義的斷言。
n??死亡測試。
n??致命和非致命的失敗。
n??值參數(shù)化測試。
n??類型參數(shù)化測試。
n??運行測試的各種選項。
n??XML測試報告的生成。
4.4????用法
4.4.1????簡單的測試
創(chuàng)建一個測試:
1.?????????使用TEST()宏來定義和命名一個測試函數(shù)。這些都是不返回值的普通C++函數(shù)。
2.?????????在這個函數(shù)中,連同你想包含的任何有效的C++語句,使用各種googletest斷言來檢查值。
3.?????????測試的結果是由斷言決定的,如果測試中的任何斷言失敗(無論是致命的還是非致命的),或者測試崩潰,整個測試就會失敗。否則,就會成功。
TEST(TestSuiteName,?TestName)?{
...?測試體?...
}
假設我們有一個簡單的函數(shù):
int?Factorial(int?n);?//?返回n的階乘。
這個功能的測試Suite:
//?測試0的階乘。
TEST(FactorialTest,?HandlesZeroInput)?{
EXPECT_EQ(Factorial(0),?1);
}
//?測試正數(shù)的階乘。
TEST(FactorialTest,?HandlesPositiveInput)?{
EXPECT_EQ(Factorial(1),?1);
EXPECT_EQ(Factorial(2),?2);
EXPECT_EQ(Factorial(3),?6);
EXPECT_EQ(Factorial(8),?40320);
}
4.4.2????Fixture
要創(chuàng)建一個Fixture:
1.?????????從::testing::Test衍生出一個類。用protected:定義它的主體,因為我們要從子類中訪問Fixture成員。
2.?????????在類的內(nèi)部,聲明計劃使用的任何對象。
3.?????????如果有必要,寫一個默認的構造函數(shù)或SetUp()函數(shù)來為每個測試準備對象。一個常見的錯誤是將SetUp()寫成Setup(),并加上一個小u--在C++11中使用override來確保拼寫正確。
4.?????????如果有必要,寫一個析構器或TearDown()函數(shù)來釋放你在SetUp()中分配的任何資源。
5.?????????如果需要,為你的測試定義子程序來共享。
當使用Fixture時,使用TEST_F()代替TEST(),允許訪問測試Fixture中的對象和子程序。
TEST_F(TestFixtureName,?TestName)?{
...?測試體?...
}
class?QueueTest?:?public?::testing::Test?{
protected:
void?SetUp()?override?{
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
//?void?TearDown()?override?{}
Queue
Queue
Queue
TEST_F(QueueTest,?IsEmptyInitially)
{
EXPECT_EQ(q0_.size(),?0);
}
TEST_F(QueueTest,?DequeueWorks)
{
int?*n?=?q0_.Dequeue();
EXPECT_EQ(n,?nullptr);
n?=?q1_.Dequeue();
ASSERT_NE(n,?nullptr);
EXPECT_EQ(*n,?1);
EXPECT_EQ(q1_.size(),?0);
delete?n;
n?=?q2_.Dequeue();
ASSERT_NE(n,?nullptr);
EXPECT_EQ(*n,?2);
EXPECT_EQ(q2_.size(),?1);
delete?n;
}
};
當這些測試運行時,會發(fā)生以下情況:
1.?????????googletest構建了一個QueueTest對象(我們稱它為t1)。
2.?????????t1.SetUp()?初始化?t1。
3.?????????第一個測試?(IsEmptyInitially)?在?t1?上運行。
4.?????????t1.TearDown()?在測試結束后進行清理。
5.?????????t1被銷毀。
6.?????????在另一個QueueTest對象上重復上述步驟,這次運行DequeueWorks測試。
5??????Catch2
一個現(xiàn)代的、C++-native的、只引入頭文件的、用于單元測試、TDD和BDD的測試框架,使用C++11、C++14、C++17和更高版本(或Catch1.x分支的C++03)。
Catch2是一個C++的多范式測試框架,也支持Objective-C(還有C)。它主要是作為一個單一的頭文件發(fā)布的,盡管某些擴展可能需要額外的頭文件。
5.1????官方網(wǎng)站
https://github.com/catchorg/Catch2
5.2????許可
Boost Software License 1.0
5.3????主要特點
n??快速且非常容易上手。只需下載catch.hpp,#include它就可以了。
n??沒有外部依賴性。只要你能編譯C++11,并且有一個C++標準庫就可以使用。
n??可把測試用例寫成:自注冊的,函數(shù)或者方法。
n??將測試用例劃分為若干部分,每個部分都是孤立運行的(不需要Fixture)。
n??使用BDD風格的Given-When-Then部分以及傳統(tǒng)的單元測試用例。
n??只有一個核心斷言宏用于比較。標準的C/C++運算符被用于比較,但完整的表達式被分解,并且lhs和rhs值被記錄下來。
n??測試使用自由形式的字符串來命名,不再使用嚴格標識符來命名。
n??測試可以被標記,以方便運行特設的測試組。
n??失敗可以融入Windows和Mac的調(diào)試器。
n??輸出是通過模塊化的報告對象。包括基本的文本和XML報告器。可以很容易地添加自定義報告器。
n??支持JUnit xml輸出,以便與第三方工具集成,如CI服務器。
n??提供了一個默認的main()函數(shù),但你可以提供你自己的函數(shù)來實現(xiàn)完全控制(例如,集成到你自己的測試運行器GUI中)。
n??提供了一個命令行解析器,你可以提供自己的main()函數(shù)。
n??Catch可以測試自己。
n??替代斷言宏報告失敗,但不中止測試用例。
n??浮點容差比較是通過使用一個表達式的Approx()語法建立起來的。
n??內(nèi)部和友好的宏被隔離,因此可以管理名稱沖突。
n??匹配器
5.4????用法
獲取Catch2最簡單的方法就是下載最新的單頭版本。單一頭文件是由一組單獨的頭文件合并生成的,但它仍然只是頭文件中的普通源代碼。
5.4.1????簡單的測試
#define?CATCH_CONFIG_MAIN??//?這告訴Catch提供一個main()--只在一個cpp文件中這樣做
#include?"catch.hpp"
unsigned?int?Factorial(?unsigned?int?number?)?{
return?number?<=?1???number?:?Factorial(number-1)*number;
}
TEST_CASE(?"Factorials?are?computed",?"[factorial]"?)?{
REQUIRE(?Factorial(1)?==?1?);
REQUIRE(?Factorial(2)?==?2?);
REQUIRE(?Factorial(3)?==?6?);
REQUIRE(?Factorial(10)?==?3628800?);
}
5.4.2????測試案例和區(qū)域
大多數(shù)測試框架都有一個基于類的Fixture機制。也就是測試用例映射到類上的方法,常見的設置和拆解可以在setup()和?teardown()方法中進行(或者在C++等支持的構造函數(shù)/析構函數(shù))。
Catch采用了一種不同的方法(與NUnit和xUnit都不同),它更自然地適合C++和C語言家族。
TEST_CASE(?"vector的尺寸和容量可以調(diào)整",?"[vector]"?)?{
std::vector
REQUIRE(?v.size()?==?5?);
REQUIRE(?v.capacity()?>=?5?);
SECTION(?"調(diào)整尺寸和容量"?)?{
v.resize(?10?);
REQUIRE(?v.size()?==?10?);
REQUIRE(?v.capacity()?>=?10?);
}
SECTION(?"縮小尺寸但不改變?nèi)萘??)?{
v.resize(?0?);
REQUIRE(?v.size()?==?0?);
REQUIRE(?v.capacity()?>=?5?);
}
SECTION(?"增加容量但不改變尺寸"?)?{
v.reserve(?10?);
REQUIRE(?v.size()?==?5?);
REQUIRE(?v.capacity()?>=?10?);
}
SECTION(?"縮小尺寸或者容量"?)?{
v.reserve(?0?);
REQUIRE(?v.size()?==?5?);
REQUIRE(?v.capacity()?>=?5?);
}
}
對于每個SECTION,從一開始就執(zhí)行TEST_CASE,?所以當我們進入每個SECTION時,我們知道大小是5,容量至少是5。我們用頂層的REQUIREs強制執(zhí)行了這些要求。
5.4.3????BDD-風格
如果你適當?shù)孛愕臏y試用例和部分,你可以實現(xiàn)BDD式的規(guī)范結構。方案可以使用SCENARIO、GIVEN、WHEN和THEN宏來指定,這些宏分別映射到TEST_CASEs和SECTIONs。
SCENARIO(?"vector的尺寸和容量可以調(diào)整",?"[vector]"?)?{
GIVEN(?"含有一些項目的Vector"?)?{
std::vector
REQUIRE(?v.size()?==?5?);
REQUIRE(?v.capacity()?>=?5?);
WHEN(?"尺寸增加"?)?{
v.resize(?10?);
THEN(?"尺寸和容量發(fā)生變化"?)?{
REQUIRE(?v.size()?==?10?);
REQUIRE(?v.capacity()?>=?10?);
}
}
WHEN(?"尺寸減少了"?)?{
v.resize(?0?);
THEN(?"尺寸變化但是容量不變"?)?{
REQUIRE(?v.size()?==?0?);
REQUIRE(?v.capacity()?>=?5?);
}
}
WHEN(?"增加容量"?)?{
v.reserve(?10?);
THEN(?"增加容量但不增加尺寸"?)?{
REQUIRE(?v.size()?==?5?);
REQUIRE(?v.capacity()?>=?10?);
}
}
WHEN(?"減少容量"?)?{
v.reserve(?0?);
THEN(?"尺寸和容量都沒有改變"?)?{
REQUIRE(?v.size()?==?5?);
REQUIRE(?v.capacity()?>=?5?);
}
}
}
}
6??????參考
https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C++
https://www.boost.org/libs/test/
http://sourceforge.net/projects/cppunit/
https://github.com/google/googletest/
https://github.com/catchorg/Catch2
https://github.com/onqtam/doctest
https://github.com/martinmoene/lest
https://github.com/etr/liblittletest
https://github.com/mollismerx/elfspy
https://github.com/gammasoft71/xtd.tunit
http://banditcpp.github.io/bandit/
單元測試
版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。