Qt 5單元測試框架

簡述:

所謂單元測試,類似gtest,即寫接口驗證你的單元功能,屬於白盒測試。

Trolltech 公司提供了QTestLib框架,是一種基於Qt 編寫的程序或庫單元測試工具。

QTestLib 提供了單元測試框架的基本功能,並提供了針對GUI 測試的擴展功能。


QTestLib 的特性
特性 詳細描述 
輕量級  QTestlib 只包含 6000行代碼和60個導出符號 
自包含 
對於非GUI測試,QTestlib 只需要Qt核心庫的幾個符號 
快速測試
QTestlib 不需要特殊的測試執行程序,不需要爲測試而進行特殊的註冊
數據驅動測試 
一個測試程序可以在不同的測試數據集上執行多次 
基本的 GUI 測試 
QTestlib 提供了模擬鼠標和鍵盤事件的功能 
IDE 友好 
QTestlib 的輸出信息可以被 Visual Studio 和 KDevelop 解析
線程安全
錯誤報告是線程安全的、原子性的
類型安全 
對模板進行了擴展使用,防止由隱式類型轉換引起的錯誤 
易擴展 
用戶自定義類型可以容易地加入到測試數據和測試輸出中

創建一個測試的步驟是,首先繼承QObject 類並添加私有的槽。每個私有的槽就是一個測試函數,然後使用 QTest::qExec() 執行測試對象中所有測試函數。


使用QTestLib,將結果數據表加載後逐行與結果數據對比。QTestLib所有相關功能都在QTest命名空間下。


1)  在PRO文件中將testlib加入QT參數中。

2)  創建測試類:需要繼承自QObject(因爲要使用信號-槽)。

3)  創建測試條目:所有的private slots下函數都將作爲測試條目自動測試,並需要一個_data()函數提供數據。

4)  創建測試數據:QTest::addColumn(),QTest::newRow()。

5)  讀取測試數據:QFETCH()

6)  對比測試結果與預期值::QCOMPARE(),QVerify()等。

7)  啓動測試:QTest::qExec()或直接調用QTEST_APPLESS_MAIN()、QTEST_MAIN()、QTEST_GUILESS_MAIN()宏。

8)  測試Case啓動、結束事件:initTestCase(),cleanupTestCase()

9)  測試條目啓動、結束事件:init(),cleanup()

10) 測試庫:直接測試庫。

11) 測試源文件:將cpp加入Test工程,測試。


系統:Windows 7

Qt構建套件:qt-opensource-windows-x86-mingw530-5.7.0.exe

Qt Creator版本:4.0.2


1、簡單的Qt 單元測試


首先實現計算圓面積的類,然後編寫代碼檢查該類是否完成了相應的功能。


1 > 建立單元測試框架


選擇“文件”→“新建文件或項目”菜單項,出現“New Project”的對話框,選擇“其他項目”→“Qt單元測試”菜單項,單擊“Choose...”按鈕繼續。




爲測試項目命名“ 名稱 ”爲“ AreaTest ”,按嚮導單擊“ 下一步 ”按鈕,出現“ Qt 單元測試-Modules”的對話框,選擇項目需要包含的模塊




單擊“下一步”按鈕,在如圖“Qt 單元測試-Details”對話框中設置將要創建的測試類的基本信息。





2 > 計算圓面積具體實現

area.h

#ifndef AREA_H
#define AREA_H
#include <QObject>

class Area:public QObject
{
    Q_OBJECT

public:
    Area(){}
    ~Area(){}
    Area(const Area &area)
    {
        m_r = area.m_r;
    }
    Area(int r)
    {
        m_r=r;
    }
    double CountArea()
    {
        return  3.14*m_r*m_r;
    }
private:
    double m_r;
};

#endif // AREA_H


3 > 測試代碼實現

tst_testarea.cpp

#include <QString>
#include <QtTest>
#include "area.h"

class TestArea : public QObject
{
    Q_OBJECT
    
public:
    TestArea();
    
private Q_SLOTS:
    void toAreaTest(); //測試函數
};

TestArea::TestArea()
{
}

void TestArea::toAreaTest()
{
    Area area(1);  //初始化半徑爲1
    /**************************
     * 使用QVERIFY()宏判斷半徑爲1的面積是否爲3.14,由於浮點數不能
     * 直接比較,所以判斷絕對值之差小於0.0000001,則認爲結果正確。
     * QVERIFY()宏用於檢查表達式是否爲真,若爲真,則程序繼續運行,
     * 若測試失敗,程序運行終止,如果需要在測試失敗時輸出信息,
     * 則可使用QVERIFY2(condition, message),
     * QVERIFY2()在"condition"條件驗證失敗時輸出信息"message"
    **************************/
    QVERIFY(qAbs(area.CountArea()-3.14)<0.0000001);
    QVERIFY2(true, "Failure");
}

QTEST_APPLESS_MAIN(TestArea)

#include "tst_testarea.moc"

4 > 運行結果


QTEST_APPLESS_MAIN(TestArea) 宏實際上是一個main()函數,其定義如下:

#define QTEST_APPLESS_MAIN(TestObject) \
int main(int argc, char *argv[]) \
{ \
    TestObject tc; \
    QTEST_SET_MAIN_SOURCE_PATH \
    return QTest::qExec(&tc, argc, argv); \
}


實例化一個TestArea對象,然後調用 QTest::qExec()執行私有槽標識的所有測試方法;QTest是個namespace。

由運行結果可知,測試方法爲 toAreaTest() ,同時還調用了測試框架自帶的initTestCase()cleanupTestCase()

在測試框架中,有四個私有槽函數是預定義用作初始化和結束清理工作的:

initTestCase():在第一個測試函數執行前被調用。不顯式定義也會被調用。

cleanupTestCase():在最後一個測試函數執行後被調用。不顯式定義也會被調用。

init():在每個測試函數執行前被調用。不顯式定義時是不會執行的

cleanup():在每個測試函數執行後被調用。不顯式定義時是不會執行的

另外,除了QTEST_APPLESS_MAIN() 宏外,測試框架還提供了兩個類似的宏,QTEST_MAIN() QTEST_GUILESS_MAIN(),用法相同。


2、數據驅動測試


對多種邊界數據進行測試,並逐項初始化,逐項完成測試。

QTest::addColumn() 函數建立要測試的數據列。

QTest::newRow()函數添加數據行。


例子1:測試字符串轉換爲全小寫字符的功能。

1 > 建立單元測試框架

操作方法同上。
項目名稱:TestQString
測試類名:TestQString
測試槽:testToLower
生成源文件:tst_testqstring.cpp

2 > 測試代碼具體實現

tst_testqstring.cpp


#include <QString>
#include <QtTest>

class TestQString : public QObject
{
    Q_OBJECT
    
public:
    TestQString();
    
private Q_SLOTS:
    //每個private slot都是一個被QTest::qExec()自動調用的測試函數
    void testToLower();
    //testToLower_data() 用以提供測試數據。
    //初始化數據的函數名和測試函數名一樣,但增加了後綴"_data()"
    void testToLower_data();
};

TestQString::TestQString()
{
}

void TestQString::testToLower()
{
    //獲取測試數據
    QFETCH(QString,string);
    QFETCH(QString,result);
    //如果兩個參數不同,則其值會分別顯示出來
    //QCOMPARE(actual,expected)宏比較實際值和期望值。
    QCOMPARE(string.toLower(),result);
    QVERIFY2(true, "Failure");
}

void TestQString::testToLower_data()
{
    //添加測試列
    QTest::addColumn<QString>("string");
    QTest::addColumn<QString>("result");
    //添加測試數據
    QTest::newRow("lower")<<"hello"<<"hello";
    QTest::newRow("mixed")<<"heLLO"<<"hello";
    QTest::newRow("upper")<<"HELLO"<<"hello";
}
//生成能夠獨立運行的測試代碼
QTEST_APPLESS_MAIN(TestQString)

#include "tst_testqstring.moc"

3 > 測試結果





例子2:測試計算圓面積的功能

1 > 建立單元測試框架

操作方法同上。

項目名稱:AreaTest2

測試類名:TestArea

測試槽:toArea

生成源文件:tst_testarea.cpp


2 > 具體實現


area.h

#ifndef AREA_H
#define AREA_H
#include <QtCore>
#include <QObject>

class Area:public QObject
{
    Q_OBJECT

public:
    Area(){}
    ~Area(){}
    Area(const Area &area)
    {
        m_r = area.m_r;
    }
    Area(int r)
    {
        m_r=r;
    }
    double CountArea()
    {
        return  3.14*m_r*m_r;
    }
private:
    double m_r;
};
/*********************
 * Q_DECLARE_METATYPE()宏將Area定義爲元類型,這樣所有基於模板的函數都可以使用Area
 * 而QTest中用到了模板函數addColumn(),因此須使用該宏使模板函數可以識別Area類。
*********************/
Q_DECLARE_METATYPE(Area)

#endif // AREA_H

tst_testarea.cpp

#include <QString>
#include <QtTest>
#include "area.h"

class TestArea : public QObject
{
    Q_OBJECT
    
public:
    TestArea();
    
private Q_SLOTS:
    void toArea();      //測試函數名toArea()
    void toArea_data(); //初始化數據的函數名toArea_data()和測試函數名toArea()一樣,但增加了後綴_data
};

TestArea::TestArea()
{
}

void TestArea::toArea()
{
    //QFETCH()宏獲取測試數據
    QFETCH(Area,area);
    QFETCH(double,r);
    //QVERIFY()宏將根據數據的多少決定函數運行多少次
    QVERIFY(qAbs(area.CountArea()-r)<0.0000001);
    QVERIFY2(true, "Failure");
}

void TestArea::toArea_data()
{
    //定義測試數據列
    QTest::addColumn<Area>("area");
    QTest::addColumn<double>("r");
    //建立測試數據
    QTest::newRow("1")<<Area(1)<<3.14;
    QTest::newRow("2")<<Area(2)<<12.56;
    QTest::newRow("3")<<Area(3)<<28.26;
}

QTEST_APPLESS_MAIN(TestArea)

#include "tst_testarea.moc"

3 > 運行結果




3、簡單性能測試


1 > 建立單元測試框架

操作方法同上。

項目名稱:TestQString2

測試類名:TestQString2

測試槽:testBenchmark

生成源文件:tst_testqstring2.cpp


2 > 具體實現

tst_testqstring2.cpp

#include <QString>
#include <QtTest>

class TestQString2 : public QObject
{
    Q_OBJECT
    
public:
    TestQString2();
    
private Q_SLOTS:
    void testBenchmark();
};

TestQString2::TestQString2()
{
}

void TestQString2::testBenchmark()
{
    QString str("heLLO");
    // 要用來測試性能的代碼
    QBENCHMARK
    {
        str.toLower();
    }
    QVERIFY2(true, "Failure");
}

QTEST_APPLESS_MAIN(TestQString2)

#include "tst_testqstring2.moc"

3 > 運行結果



其中,0.00068 msecs per iteration (total: 90, iterations: 131072),其含義是測試代碼運行了131072次,總時間90毫秒,每次運行的平均時間爲0.00068毫秒。


4、GUI 測試


可以使用QTest::keyClick(),QTest::keyPress(),QTest::keyRelease(),QTest::mouseClick(), QTest::mouseDClick(), QTest::mouseMove(),QTest::mousePress() 和QTest::mouseRelease()函數來模擬相應的GUI事件。

樣例代碼:

UintTest 密碼:c6x5




發佈了112 篇原創文章 · 獲贊 514 · 訪問量 95萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章