本文是我從業多年開發生涯中針對線上業務的處理經驗總結而來,這些業務或多或少相信大家都遇到過,因此在這裡分享給大家,大家也可以看看是不是遇到過類似場景。本文大綱如下, 後臺上傳文件 線上後臺項目有一個消息推送的功能,運營新建一條通知消息時,需要一起上傳一列包含用戶 id 的文件,來給文件中包含的指定用 ...
9 測試&調試
調試和測試是軟體開發的重要組成部分。在本章中,你將學習如何調試 Qt 項目、不同的調試技術以及 Qt 支持的調試器。調試是發現錯誤或不希望出現的行為的根本原因並加以解決的過程。我們還將討論使用Qt Test框架進行單元測試。Qt Test是基於Qt的應用程式和庫的單元測試框架。它具有大多數單元測試框架提供的所有功能。此外,它還支持測試圖形用戶界面(GUI)。本模塊有助於以便捷的方式編寫基於 Qt 的應用程式和庫的單元測試。您還將學習使用不同圖形用戶界面測試工具測試圖形用戶界面的技巧。
具體來說,我們將討論以下主題:
- Qt中的調試
- 調試策略
- 調試C++應用程式
- 調試Qt Quick應用程式
- Qt中的測試
- 與Google的 C++ 測試框架集成
- 測試Qt Quick應用程式
- 圖形用戶界面測試工具
9.1 Qt 調試
在軟體開發過程中,經常會出現技術問題。為瞭解決這些問題,我們必須在向公眾發佈應用程式之前首先確定並解決所有問題,以保證質量和聲譽。調試是一種定位這些潛在技術問題的技術。
Qt 支持幾種不同類型的調試器。您所使用的調試器可能因您的項目所使用的平臺和編譯器而異。以下是 Qt 廣泛使用的調試器列表:
- GNU 符號調試器(GDB)是由 GNU 項目開發的跨平臺調試器。
- Microsoft Console Debugger (CDB) 是 Microsoft 為 Windows 開發的調試器。
- 低級虛擬機調試器(LLDB)是由 LLVM 開發人員小組開發的跨平臺調試器。
- QML/JavaScript Debugger 是 Qt 公司提供的 QML 和 JavaScript 調試器。
如果您在 Windows 上使用 MinGW 編譯器,則無需手動設置GDB,因為它通常包含在 Qt 安裝中。如果您使用的是Linux等其他操作系統,則可能需要在將其鏈接到 Qt Creator之前手動安裝。Qt Creator會自動檢測 GDB 的存在,並將其添加到調試器列表中。
你也可以使用Valgrind來調試你的應用程式。你可以指定 --vgdb=yes 或 --vgdb=full 來激活 Valgrind gdbserver。你可以指定 --vgdb-error=number 來在顯示一定數量的錯誤後激活 gdbserver。如果將該值設為 0,gdbserver 將在初始化時激活,這樣就可以在程式啟動前設置斷點。值得註意的是,Valgrind 發行版中已包含vgdb。無需單獨安裝。
Windows可安裝 CDB。預設情況下,Visual Studio 的內置調試器不可用。因此,您必須單獨安裝CDB調試器,方法是在安裝 Windows SDK 時將 Windows 的調試工具選為可選組件。Qt Creator 通常會識別 CDB 的存在,並將其添加到選項下的調試器列表中。
Android 調試比在普通桌面環境中調試更具挑戰性。Android開發需要不同的軟體包,如JDK、Android SDK 和 Android NDK。在桌面平臺上,需要使用 Android Debug Bridge(ADB)驅動程式才能進行 USB 調試。您必須在 Android 設備上啟用開發者模式並接受 USB 調試才能繼續。
MacOS 和 iOS 上使用的調試器是 LLDB。它預設包含在 Xcode 中。Qt Creator 會自動檢測它的存在,並將其與工具包鏈接。如果您熟悉調試器並知道自己在做什麼,也可以將非 GDB 調試器添加到您最喜歡的集成開發環境中。
調試器插件會根據機器上可用的調試器為每個軟體包確定一個合適的本地調試器。你可以通過添加新調試器來剋服這種偏好。如圖 9.1 所示,你可以在 "選項 "菜單下的 "工具包 "設置中的 "調試器 "選項卡中找到可用的調試器:
9.2 調試策略
有不同的調試策略可以找到問題的根本原因。在嘗試查找應用程式中的錯誤之前,徹底瞭解程式或程式庫至關重要。如果不瞭解自己在做什麼,就無法發現錯誤。只有徹底瞭解系統及其運行方式,才能找出應用程式中的錯誤。以往的經驗有助於發現類似類型的錯誤以及解決錯誤。專家個人的知識決定了開發人員可以多容易地找到錯誤。您可以添加調試列印語句和斷點來分析程式的流程。您可以進行前向分析或後向分析,以跟蹤錯誤的位置。
調試時,可通過以下步驟找到根本原因並加以解決:
- 確定問題。
- 定位問題。
- 分析問題。
- 解決問題。
- 修複副作用。
無論使用哪種編程語言或平臺,調試應用程式時最重要的是要知道是哪段代碼導致了問題。您可以通過多種方式找到有問題的代碼。
如果缺陷是由質量保證團隊或用戶提出的,那麼可以詢問問題發生的時間。查看日誌文件或任何錯誤信息。註釋掉代碼中可疑的部分,然後再次構建並運行應用程式,看看問題是否仍然存在。如果問題可以重現,則在找到導致問題的代碼行之前,通過列印信息和註釋代碼行進行正向和反向分析。
還可以在內置調試器中設置斷點,搜索目標功能中的變數變化。如果某個變數更新到了意外值,或者某個對象指針變成了無效指針,那麼你就可以很容易地識別出來。檢查安裝程式中使用的所有模塊,確保您和用戶使用的應用程式版本號相同。如果使用的是不同的版本或不同的分支,那麼請檢查帶有指定版本標記的分支,然後調試代碼。
9.3 調試C++應用程式
QDebug類可用於將變數值列印到應用程式輸出視窗。QDebug類似於標準庫中的std::cout,它是Qt的一部分,支持 Qt 類,無需轉換即可顯示其值。
要啟用調試信息,我們必須包含 QDebug 頭文件。
Qt 提供了多個全局巨集,用於生成不同類型的調試信息。它們可用於以下不同目的:
- qDebug() 提供自定義調試信息。
- qInfo() 提供信息消息。
- qWarning() 報告警告和可恢復錯誤。
- qCritical() 提供關鍵錯誤信息並報告系統錯誤。
- qFatal() 在退出前提供致命錯誤信息。
使用qDebug()可以查看功能是否正常運行。查找完錯誤後,刪除包含qDebug()的代碼行,以避免出現不必要的控制台日誌。讓我們通過一個例子來看看如何使用 qDebug()在輸出窗格中列印變數。創建一個示例QWidget應用程式,添加函數 setValue(int value),併在函數定義中添加以下代碼:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
setValue(100);
}
Widget::~Widget()
{
delete ui;
}
void Widget::setValue(int value)
{
qDebug()<<"Value is:" <<value;
}
執行後控制台會有輸出:
可通過調試菜單-開始調試 啟動調試:
你也可以點擊行號來添加斷點。點擊行號設置斷點。你會看到行號上出現一個紅點。
接下來,按鍵盤上的 F5 鍵或單擊啟動調試按鈕。在調試模式下運行應用程式後,你會發現第一個紅點的頂部出現了一個黃色箭頭:
調試器在第一個斷點處停止。現在,變數及其含義和類型將顯示在 Qt Creator 右側的 Locals 和 Expression 視窗中。
這種方法可用於快速檢查應用程式。要移除斷點,只需再次點擊紅點圖標或從右鍵上下文菜單中點擊即可。
您可以在以下文檔中瞭解更多特性及其用法:https://doc.qt.io/qt-6/debug.html
重要提示:某些防病毒程式會阻止調試器獲取信息。Avira 就是這樣一種反病毒軟體。如果在生產 PC 上安裝了 Avira,在 Windows 平臺上調試器的啟動可能會失敗。
下一節,我們將討論如何調試 Qt Quick 應用程式並查找 QML 文件中的問題。
9.4 調試 Qt Quick 應用程式
在上一節中,我們討論瞭如何調試 C++ 代碼。但你可能仍想知道如何調試用QM 編寫的代碼。
就像 QDebug 類一樣,QML 中也有不同的控制台 API 可用於調試。它們如下:
- 日誌(Log): 用於列印一般信息。
- Assert: 用於驗證表達式。
- Timer:用於測量調用之間的時間間隔。
- Trace 用於列印 JavaScript 執行的堆棧跟蹤。
- Count用於查找函數的調用次數。
- Profile: 用於剖析 QML 和 JavaScript 代碼。
- Exception 異常 用於列印錯誤信息。
控制台 API 提供了幾個方便的函數來列印不同類型的調試信息,如 console.log()、console.debug()、console.info()、console.warn() 和 console.error()。您可以按以下方式列印帶有參數值的信息:console.log("Value is:", value)
您還可以通過在 Components.onCompleted:{...} 內添加信息來檢查組件的創建情況:
Components.onCompleted: {
console.log("Component created")
}
要驗證表達式是否為真,可以使用 console.assert(),例如下麵的例子:
console.assert(value == 100, "Reached the maximum limit");
console.time() 和 console.timeEnd() 會記錄調用之間的時間間隔。console.trace() 會列印 JavaScript 在調用階段的堆棧跟蹤。函數名、文件名、行數和列數都包含在堆棧跟蹤詳情中。
console.count() 會返回一段代碼的當前執行次數以及一條信息。使用 console.profile()會激活QML和JavaScript分析,調用 console.profileEnd()則會停用。你可以使用 console.exception() 來列印錯誤信息和 JavaScript 執行的堆棧跟蹤。
添加斷點的方法與前一節討論的相同,如下所示:
- 要進入堆棧中的代碼,請單擊工具欄上的 "進入"(Step Into)按鈕或按 F11 鍵。
- 要退出代碼,請按 Shift + F11。要點擊斷點,在方法末尾添加一個斷點,然後點擊 Continue(繼續)。
- 打開 QML 調試器控制台輸出窗格,在當前上下文中運行 JavaScript 命令。
您可以在運行 Qt Quick 應用程式時發現問題並觀察數值。它將幫助你找到導致意外行為並需要修改的代碼部分。
9.5 Qt中的測試
單元測試是一種使用自動化工具測試簡單應用程式、類或函數的方法。我們將討論什麼是單元測試,以及為什麼要進行單元測試,然後再討論如何使用Qt Test將單元測試納入我們的方法中。單元測試是將應用程式分解為最小的功能單元,然後在程式框架內用實際情況測試每個單元的過程。單元是應用程式中可測試的最小組件。程式設計中的單元測試通常側重於功能或流程。
面向對象程式設計中的單元通常是介面、類或函數。單元測試能在實施過程的早期發現問題。這包括程式員實現過程中的故障,以及單元規範中的缺陷或不完整部分。在創建過程中,單元測試是由待測單元的開發人員開發的簡短代碼片段。有許多單元測試工具可用於測試C++代碼。讓我們探討一下Qt測試框架的優勢和特點。
9.5.1 Qt中的單元測試
Qt Test是基於Qt的應用程式和庫的單元測試平臺。Qt Test包括傳統單元測試應用程式中的所有功能,以及用於測試圖形用戶界面的插件。它有助於使為基於Qt的程式和庫編寫單元測試變得更加容易。
以前,單元測試可能需要手動完成,尤其是圖形用戶界面測試,但現在有一種工具可以讓您編寫代碼來自動驗證代碼,這初看起來可能有悖常理,但卻能正常工作。Qt Test是一個專門的測試框架,用於基於Qt的單元測試。
要使用Qt內置的單元測試模塊,必須在項目文件(.pro)中添加 testlib:QT += core testlib
接下來,運行 qmake 為項目添加可用模塊。為了讓測試系統找到並實現它,你必須使用QTest頭文件,並將測試函數聲明為私有槽。QTest頭包含與Qt Test相關的所有函數和語句。要使用QTest功能,只需在 C++ 文件中添加以下一行即可:#include
您應為每一種可能的情況編寫測試用例,然後在每次更改基線代碼時運行測試,以確保系統繼續按預期運行。這是一個非常有用的工具,可確保任何程式更新都不會破壞現有功能。
讓我們使用Qt Creator 的內置嚮導創建簡單的測試應用程式。從新建項目菜單中選擇自動測試項目:
測試代碼 tst_testclass.cpp
#include <QtTest>
// add necessary includes here
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass() {}
~TestClass(){}
private slots:
void initTestCase(){}
void cleanupTestCase() {}
void test_compareStrings();
void test_compareValues();
};
void TestClass::test_compareStrings()
{
QString string1 = QLatin1String("Apple");
QString string2 = QLatin1String("Orange");
QCOMPARE(string1.localeAwareCompare(string2), 0);
}
void TestClass::test_compareValues()
{
int a = 10;
int b = 20;
int result = a + b;
QCOMPARE(result,30);
}
QTEST_APPLESS_MAIN(TestClass)
#include "tst_testclass.moc"
要執行所有測試用例,必須在文件底部添加 QTEST_MAIN() 等巨集。QTEST_MAIN() 巨集擴展為一個簡單的 main() 方法,可運行所有測試函數。QTEST_APPLESS_MAIN() 巨集適用於不使用 QApplication 對象的簡單獨立非圖形用戶界面測試。如果不需要圖形用戶界面,但需要事件迴圈,則使用 QTEST_GUILESS_MAIN():
為了使測試用例成為獨立的可執行文件,我們添加了 QTEST_APPLESS_MAIN() 巨集和該類的 moc 生成文件。您還可以使用其他一些巨集來測試應用程式。如需瞭解更多信息,請訪問以下鏈接:http://doc.qt.io/qt-6/qtest.html#macros
運行前面的示例時,您將看到如下所示的測試結果輸出:
還可以從 Qt Creator菜單欄的工具-測試-運行所有測試)選項運行所有測試執行。
您還可以在左側的項目瀏覽器視圖中查看所有測試用例。從項目瀏覽器下拉菜單中選擇測試。您可以在此視窗中啟用或禁用某些測試用例。
您可以使用幾個QTest便捷函數來模擬圖形用戶界面事件,如鍵盤或滑鼠事件。讓我們通過一個簡單的代碼片段來瞭解它們的用法:
QTest::keyClicks(testLineEdit, "Enter");
QCOMPARE(testLineEdit->text(), QString("Enter"));
在前面的代碼中,測試代碼在行編輯控制項上模擬鍵盤文本輸入事件,然後驗證輸入的文本。您還可以使用 QTest::mouseClick() 模擬滑鼠點擊事件。使用方法如下:
QTest::mouseClick(testPushBtn, Qt::LeftButton);
Qt 的測試框架在測試驅動開發(TDD)中也很有用。在 TDD 中,您首先要編寫測試,然後再編寫實際邏輯代碼。由於沒有實現,測試最初會失敗。然後,在繼續下一個測試之前,編寫通過測試所需的最基本代碼。這就是在實現必要功能之前迭代開發功能的方法。
參考資料
- 軟體測試精品書籍文檔下載持續更新 https://github.com/china-testing/python-testing-examples 請點贊,謝謝!
- 本文涉及的python測試開發庫 謝謝點贊! https://github.com/china-testing/python_cn_resouce
- python精品書籍下載 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
- Linux精品書籍下載 https://www.cnblogs.com/testing-/p/17438558.html
- https://wiki.qt.io/Building_Qt_Creator_from_Git_on_Ubuntu_22.04
9.6 與Google C++測試框架集成
GoogleTest是由Google開發的測試和模擬框架。GoogleMock項目已併入GoogleTest。GoogleTest需要至少支持C++11標準的編譯器。它是一個跨平臺測試框架,支持 Windows、Linux 和 macOS 等主要桌面平臺。它能幫助你編寫更好的 C++ 測試,並具有模擬等高級功能。您可以將 Qt Test 與 GoogleTest 集成,以獲得兩個框架的最佳效果。如果你打算同時使用這兩個測試框架的功能,那麼你應該使用 GoogleTest 作為主要的測試框架,而在測試用例中,你可以使用 Qt Test 的功能。
Qt Creator 內置支持 GoogleTest。你可以在選項界面的測試部分找到 Google Test 選項卡,並設置全局 GoogleTest 偏好,如圖 9.10 所示:
您可以從以下鏈接下載 GoogleTest 源代碼:https://github.com/google/googletest。您可以從以下文檔中瞭解更多有關功能及其使用的信息:https://google.github.io/googletest/primer.html
下載源代碼後,請先構建庫,然後再創建示例應用程式。您也可以在構建測試項目的同時構建統一的 GoogleTest 源代碼。生成庫後,請按照以下步驟運行 GoogleTest 應用程式:
本節以下內容後續補齊。
9.7 測試Qt Quick應用程式
Qt Quick Test 是為 Qt Quick 應用程式的單元測試而創建的框架。測試用例使用JavaScript編寫,並使用 TestCase QML 類型。名稱以test_開頭的函數被識別為需要執行的測試用例。測試工具會遞歸搜索所需源目錄中的 tst_ *.qml 文件。您可以將所有測試 .qml 文件放在一個目錄下,並定義 QUICK_TEST_SOURCE_DIR。如果未定義該目錄,則在執行測試時將只包含當前目錄下的 .qml 文件。Qt 並不確保 Qt 快速測試模塊的二進位相容性。您必須使用相應版本的模塊。
要開始執行測試用例,必須在 C++ 文件中添加 QUICK_TEST_MAIN(),如下所示:
#include <QtQuickTest>
QUICK_TEST_MAIN(testqml)
您需要添加 qmltest 模塊以啟用 Qt 快速測試。在 .pro 文件中添加以下代碼行:
QT += qmltest
TEMPLATE = app
TARGET = tst_calculations
CONFIG += qmltestcase
SOURCES += testqml.cpp
讓我們看一個基本算術計算的演示,瞭解模塊是如何工作的。我們將進行一些計算,如加法、減法和乘法,並故意犯一些錯誤,使測試用例失敗:
本節以下內容後續補齊。
9.8 圖形用戶界面測試工具
您可以輕鬆地將一個或多個類作為單元測試進行評估,但我們必須手動編寫所有測試用例。圖形用戶界面測試尤其具有挑戰性。我們如何才能在不使用C++或QML編碼的情況下記錄用戶交互(如滑鼠點擊)?這個問題一直困擾著開發人員。市場上有許多圖形用戶界面測試工具可以幫助我們做到這一點。其中有些工具價格昂貴,有些則是開源的。我們將在本節中討論幾種這樣的工具。
不過,你可能並不需要一個完整的圖形用戶界面測試框架。有些問題可以通過簡單的技巧來解決。例如,在使用圖形用戶界面時,您可能還需要檢查不同的屬性,如視覺元素的對齊方式和邊界。最簡單的方法之一就是添加一個矩形來檢查邊界,如下麵的代碼所示:
在前面的示例中,您可以看到文本元素被置於矩形的中心位置,並帶有藍色邊框。如果沒有藍色邊框,你可能會想,為什麼文本元素沒有放在圖形用戶界面的中心位置。你還可以看到每個元素的邊界和邊距。當文本元素寬度小於字體寬度時,就會出現剪切現象。您還可以發現用戶界面元素之間是否存在重疊區域。這樣,就可以在不使用 SG_VISUALIZE 環境變數的情況下發現圖形用戶界面中特定元素的問題。
下麵我們來討論幾個圖形用戶界面測試工具。
9.8.1 Linux 桌面測試項目(LDTP Linux Desktop Testing Project)
Linux桌面測試項目(LDTP)為測試和改進 Linux 桌面平臺提供了高質量的測試自動化基礎架構和尖端工具。LDTP是一個圖形用戶界面測試框架,可在所有平臺上運行。它使用可訪問性庫對應用程式的用戶界面進行探查。該框架還包括根據用戶與圖形用戶界面的交互方式記錄測試用例的工具。
要點擊按鈕,請使用以下語法:
click('<window name>','<button name>')
要獲取給定對象的當前滑塊值,請使用以下代碼:
getslidervalue('<window name>','<slider name>')
要在 GUI 應用程式中使用 LDTP,您必須為所有QML對象添加一個可訪問名稱。您可以使用對象名稱作為可訪問名稱,如下所示:
Button {
id: quitButton
objectName: "quitButton"
Accessible.name: objectName
}
在前面的代碼中,我們為 QML 控制項添加了一個可訪問名稱,這樣 LDTP 工具就能找到這個按鈕。LDTP 需要用戶界面的視窗名稱來定位子控制項。假設視窗名稱是 Example,那麼要生成點擊事件,請在 LDTP 腳本中使用以下命令:
>click('Example','quitButton'
前面的 LDTP 命令找到了 quitButton 並生成了一個按鈕點擊事件。您可以通過以下鏈接瞭解更多有關其功能和用途的信息:https://ldtp.freedesktop.org/user-doc/
9.8.2 GammaRay
KDAB 開發了一款名為 GammaRay 的軟體自省工具,用於檢查 Qt 應用程式。您可以使用 QObject 自省機制在運行時觀察和操作應用程式。它既能在本地機器上運行,也能在遠程嵌入式目標上運行。它擴展了指令級調試器的功能,同時遵循與底層框架相同的標準。這對於使用場景圖、模型/視圖、狀態機等框架的複雜項目尤其有用。有多種工具可用於檢查對象及其屬性。然而,GammaRay 與 Qt 複雜框架的深度關聯使其從眾多工具中脫穎而出。
您可以從以下鏈接下載 GammaRay:https://github.com/KDAB/GammaRay/wiki/Getting-GammaRay
您可以從以下鏈接瞭解更多有關其功能和用途的信息:https://www.kdab.com/development-resources/qt-tools/gammaray/
9.8.3 Squish
Squish是一款跨平臺圖形用戶界面自動化測試工具,適用於桌面、移動、嵌入式和網路應用程式。您可以對使用 Qt Widgets 或 Qt Quick 編寫的跨平臺應用程式進行圖形用戶界面自動化測試。全球數以千計的企業使用 Squish 通過功能回歸測試和系統測試來測試圖形用戶界面。
您可以通過以下鏈接瞭解有關該工具的更多信息:https://www.froglogic.com/squish/
在本節中,我們討論了各種圖形用戶界面測試工具。探索它們,併在你的項目中嘗試使用。讓我們總結一下本章的學習內容。
9.9 總結
在本章中,我們瞭解了什麼是調試,以及如何使用不同的調試技術來識別 Qt 應用程式中的技術問題。除此之外,我們還瞭解了 Qt 在不同操作系統上支持的各種調試器。最後,我們學習瞭如何使用單元測試來簡化某些調試措施。我們討論了單元測試,並學習瞭如何使用 Qt 測試框架。你還看到瞭如何調試 Qt Quick 應用程式。我們還討論了 Qt 支持的其他各種測試框架和工具。現在,您可以為自定義類編寫單元測試。如果有人不小心修改了某些特定邏輯,單元測試就會失敗並自動報警。
釘釘或微信號: pythontesting 微信公眾號:pythontesting