博客地址已更改,文章數量較多不便批量修改,若想訪問源文請到 coologic博客 查閱,網址:www.coologic.cn
如本文記錄地址為 techieliang.com/A/B/C/ 請改為 www.coologic.cn/A/B/C/ 即可查閱
版權聲明:若無來源注明, Techie亮博客文章均為原創。 轉載請以鏈接形式標明本文標題和地址:
本文標題:Qt單元測試(QTestLib) 本文地址: http://techieliang.com/2017/12/483/
1. 創建
QTestLib框架提供了一個簡單易用的單元測試框架,需要在工程文件中添加Qt+=testlib,或在新建項目是選擇“其他項目-qt單元測試”,詳細幫助請看qt4.8官方文檔,Qt5官方文檔
2. 基本操作
- class Untitled2Test : public QObject {
- Q_OBJECT
- public:
- Untitled2Test();
- private Q_SLOTS:
- void initTestCase();
- void cleanupTestCase();
- void testCase1();
- };
- Untitled2Test::Untitled2Test() {
- }
- void Untitled2Test::initTestCase() {
- }
- void Untitled2Test::cleanupTestCase() {
- }
- void Untitled2Test::testCase1() {
- QVERIFY2(true, "Failure");
- }
- QTEST_APPLESS_MAIN(Untitled2Test)
- #include "tst_untitled2test.moc"
注意:
1、每一個測試類(Case)中的每一項測試條目必須在Qt槽中,否則無法調用“private Q_SLOTS:”“private slots:”均可
2、最后兩行必須有,單元測試不具有Main函數,使用此函數實現自動添加並調用所有槽
1、initTestCase()
will be called before the first testfunction is executed.initTestCase()會在第一個測試函數執行前調用。
2、cleanupTestCase()
will be called after the last testfunction was executed.cleanupTestCase()會在最后一個測試函數執行后調用。
3、init()
will be called before each testfunction is executed.init()會在每一個測試函數執行前調用。
4、cleanup()
will be called after every testfunction.cleanup()會在每一個測試函數執行后調用。
3. 高級操作
3.1. 命令行操作-可以輸出調試結果到文本
打開cmd,通過cd命令將目錄指向到項目的debug目錄下的debug,在此文件內應該可以直接看到測試項目的可執行exe文件,此時出入tst_qttesttest -xml -vs -lightxml -o testres.txt指令即可導出測試結果保存到texstres.txt文件中。
其中tst_qttesttest為測試項目對應的可執行文件名。
還可以使用以下命令行參數:
-
- -help
輸出可能的命令行參數,並提供一些有益的幫助。 - 的功能
輸出在測試中所有測試功能。 - -O?文件名
??寫輸出到指定的文件,而不是標准輸出 - 無聲的
沉默輸出,只顯示警告,失敗和最小的狀態消息 - -V1
詳細輸出,輸出的進入和退出測試功能的信息。 - -V2
擴展的詳細輸出;還輸出每個QCOMPARE()和QVERIFY() - -VS
輸出每個被發出的信號 - -XML
輸出XML格式的結果,而不是純文本 - lightxml
輸出結果作為XML標簽流 - -eventdelay?毫秒
延遲,如果沒有模擬鍵盤或鼠標(指定QTest :: keyClick(),QTest ::mouseClick()等),從這個參數的值(以毫秒為單位)取代。 - keydelay?MS
類似eventdelay,但只影響模擬鍵盤而不是鼠標模擬。 - mousedelay?MS
類似eventdelay,但只影響鼠標模擬,而不是鍵盤模擬。 - -KeyEvent的詳細
輸出更詳細的輸出模擬鍵盤 - – maxwarnings
numberBR設置輸出最大數量的警告。無限,默認為0到2000。
- -help
3.2. GUI測試
Qtestlib單元測試提供GUI操作函數,可對控件發送消息后檢測執行結果,比如QTest::keyClick(),QTest::mouseClick()等等,詳情請見幫助文檔
下面提供鼠標操作相關的枚舉類型:
Constant | Value | Description |
---|---|---|
QTest::MousePress |
0 |
A mouse button is pressed. |
QTest::MouseRelease |
1 |
A mouse button is released. |
QTest::MouseClick |
2 |
A mouse button is clicked (pressed and released). |
QTest::MouseDClick |
3 |
A mouse button is double clicked (pressed and released twice). |
QTest::MouseMove |
4 |
The mouse pointer has moved. |
下面為鼠標相關的操作函數:
- void mouseClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
- void mouseClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
- void mouseDClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
- void mouseDClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
- void mouseMove(QWidget *widget, QPoint pos = QPoint(), int delay = -1)
- void mouseMove(QWindow *window, QPoint pos = QPoint(), int delay = -1)
- void mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
- void mousePress(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
- void mouseRelease(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
- void mouseRelease(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), QPoint pos = QPoint(), int delay = -1)
3.3. 結果可視化-AutoTest插件
默認測試結果顯示在控制台(應用程序輸出標簽)以純文本形式顯示,不夠直觀,可使用AutoTest插件實現可視化效果
通過幫助-關於插件-AutoTest開啟即可,啟動此插件需要重啟Qt Creator,然后再下方會多出TestResults的標簽,可直接在此標簽點擊上方的運行按鈕運行所有測試,同時在“工具-Test”也可運行所有測試
此插件可以在運行單元測試后以紅、綠色表示明確標記處運行結果,並且以Case為單位顯示,可以展開看到具體每一個測試用例的結果。
3.4. 可以用到的測試宏命令
- QBENCHMARK
- QBENCHMARK_ONCE
- QCOMPARE(actual, expected)
- QEXPECT_FAIL(dataIndex, comment, mode)
- QFAIL(message)
- QFETCH(type, name)
- QFINDTESTDATA(filename)
- QSKIP(description)
- QTEST(actual, testElement)
- QTEST_APPLESS_MAIN(TestClass)
- QTEST_GUILESS_MAIN(TestClass)
- QTEST_MAIN(TestClass)
- QTRY_COMPARE(actual, expected)
- QTRY_COMPARE_WITH_TIMEOUT(actual, expected, timeout)
- QTRY_VERIFY2(condition, message)
- QTRY_VERIFY(condition)
- QTRY_VERIFY2_WITH_TIMEOUT(condition, message, timeout)
- QTRY_VERIFY_WITH_TIMEOUT(condition, timeout)
- QVERIFY2(condition, message)
- QVERIFY(condition)
- QVERIFY_EXCEPTION_THROWN(expression, exceptiontype)
- QWARN(message)
3.5. 單元測試注意事項
- 單元測試類中建議不要出現私有成員,尤其是指針,同時不建議在測試函數中建立被測類的指針,而是直接建立被測類的對象,在測試結束后容易遺忘指針。若需要指針
initTestCase
中new,在cleanupTestCase
中delete。 - 若某個測試函數中出現了new,一定記着delete,且務必讓delete在第一個斷言前出現,因為斷言失敗函數就回立刻結束,並把當前函數標記為測試失敗。若delete在第一個斷言之后,而第一個斷言失敗則不會執行之后的delete。
- 若測試類必須有私有成員,必須注意一個測試類中的所有函數公用私有成員,不會在每個測試之前刷新狀態。
3.6. 被測類為單例時
若被測類為單例,欲對其內所有函數做單元測試,會出現測試第一個函數可以保證測試環境為初始狀態,后續測試回因為單例的原因,導致測試時建立在之前操作后的環境下。欲解決此問題,需要刪除單例。
單例類如下:
- class SingleModel {
- public:
- static inline SingleModel* get_instance() {
- if (m_instance == nullptr) {
- m_instance = new SingleModel();
- }
- return m_instance;
- };
- private:
- SingleModel();
- class SingletonDel {
- public:
- ~SingletonDel() {
- if (m_instance != nullptr) {
- delete m_instance;
- m_instance = NULL;
- }
- }
- };
- static SingleModel* m_instance;
- static SingletonDel m_singleton_del;
- };
此時使用get_instance可以獲得單例的指針,使用delete可以刪除單例的空間,但是由於單例實例的指針是靜態私有成員的,所以應該將其設置為NULL,否則下次調用get_instance判斷非NULL會直接返回之前的已經被刪除的空間指針而不進行new操作,導致后續操作錯誤。
由於m_instance是私有成員,在單元測試時無法進行修改,故做以下設置:
.h文件不變:
- #include <QtTest>
- class ProjectModelTest: public QObject {
- Q_OBJECT
- private Q_SLOTS:
- void TestXXX();
- };
.cpp文件修改:
- #define private public
- #include "project_model.h"
- void ProjectModelTest::TestXXX() {}
注意一定要在include前define,通過將private定義為public,從而實現將源程序的私有成員編程public。同時此處的define在cpp里面,只對此cpp有效,不會影響其余的單元測試。