Qtでのユニットテスト



ゴラムは、画像のテキストにエラーがあることに気づきました



敬礼、ハブル! お元気ですか?



私は少し何かを学びたかった。 Qtでのユニットテストに関する少なくともいくつかの投稿のために、Qt Softwareハブのハブを見ていました。 見つかりません。 ここでは、Qtでの単体テストに関する基本的なことを説明します(強力なシャーマニズムを期待しないでください)。 実際、Qtでの単体テストは非常に簡単です。 これを行う方法を学ぶには、さらに読むことをお勧めします。



私はすべてをバラバラに分解しようとします。 いわば、グループ化します。 始めましょう。



理論



単体テストの理論を知っている場合は、この点をスキップできます。



コードがあります。 どのようにそれを望んでも、バグがあります。 バグは悪いです。 バグを回避するには、非常に高品質のコードを作成する必要があり(この記事には記載されていません)、最も重要なこととして、 テストします。 しかし、コードを記述し、補足し、リファクタリングします...そして、プロジェクトの各バージョンを同じテストセットにサブミットするたびに不快です。 そして、ここで非常に賢明なプログラマーは、この大事な一連のテストでプログラムをテストできるようなプログラムを作成することを考えました。 そして、このテストモデルはユニットテストと呼ばれています!



Qtでの単体テスト



そして今、より具体的に。 Qtでは、QTestLibモジュール(testlib)がユニットテストを担当します。 テスト用の一連のマクロを提供します。 しかし、それについては後で。 いくつかのテスト方法があります。





私は最初の方法をより頻繁に使用しますが、2番目の方法はいです。 しかし、今日は2番目の方法の例を示し、最初の方法を記述します。



Qtはクールなモデルを使用します:1つのプロジェクト-1つのテスト。 したがって、テストは、メインプロジェクトのテストの子ディレクトリにテストプロジェクトを作成することで実装されます。 テストには、メインクラスのテストを実装するクラスがあります。 後でどのように機能するかを学習しますが、このアプローチの主な違いはテストの実行方法にあります。 このアプローチでは、main.cppがなく、test_classname.cppの最後にマクロQ_TEST_MAIN(Test_ClassName)が存在する必要があります。



挑戦する



たとえば、整数の比較で機能するSmartクラスを実装することを提案します。 彼は具体的に何をしますか? より小さい数値を返すint min(int、int)メソッドを実装し、より大きい数値を返すint max(int、int)メソッドを実装します。



じゃあもう!



だから Qt Creatorに移動します。 コンソールQtアプリケーションを作成します。 testlibおよびguiモジュール(GUIのテストに必要)を.proファイルに追加します。 これで開始できます。 テストを書いてからクラス自体を書くのが慣習ですが、おそらく伝統から逸脱するでしょう。 Smartクラスを作成します。 あなたは幸運です、私はそれを書きます。 あなたはそれがどのように機能するかを理解する必要があります。 ここにこのハンサムな男がいます:



smart.h

#ifndef SMART_H #define SMART_H #include <QObject> #include <QStringList> class Smart : public QObject { Q_OBJECT public: explicit Smart(QObject *parent, const QStringList& list); public slots: int max(int a, int b); int min(int a, int b); }; #endif // SMART_H
      
      







smart.cpp

 #include "smart.h" Smart::Smart(QObject *parent, const QStringList& list) : QObject(parent) { } int Smart::max(int a, int b) { if(a > b) return a; return b; } int Smart::min(int a, int b) { if(a < b) return a; return b; }
      
      







QObject *クラスのテスト



クラスの準備ができました。 それがどのように機能するかをチェックする時です! これを行うために、「スマート」クラスをテストするクラスを作成します。 Test_Smartと呼ばれます。



test_smart.h

 #ifndef TEST_SMART_H #define TEST_SMART_H #include <QObject> class Test_Smart : public QObject { Q_OBJECT public: explicit Test_Smart(QObject *parent = 0); private slots: //    void max(); // int max(int, int) }; #endif // TEST_SMART_H
      
      







test_smart.cpp

 #include <QTest> #include "test_smart.h" #include "smart.h" Test_Smart::Test_Smart(QObject *parent) : QObject(parent) { } void Test_Smart::max() { Smart a; QCOMPARE(a.max(1, 0), 1); QCOMPARE(a.max(-1, 1), 1); QCOMPARE(a.max(4, 8), 8); QCOMPARE(a.max(0, 0), 0); QCOMPARE(a.max(1, 1), 1); QCOMPARE(a.max(-10,-5), -5); }
      
      







少しは終わりませんでしたが、怖くないです。 まだ時間があります。 次に、テストの実行方法を学習する必要があります。



main.cpp

 #include <QApplication> #include <QTest> #include <iostream> #include <cstdlib> #include <cstdio> #include "test_smart.h" using namespace std; int main(int argc, char *argv[]) { freopen("testing.log", "w", stdout); QApplication a(argc, argv); QTest::qExec(new Test_Smart, argc, argv); return 0; }
      
      







コンパイル...



testing.log

 ********* Start testing of Test_Smart ********* Config: Using QTest library 4.8.1, Qt 4.8.1 PASS : Test_Smart::initTestCase() PASS : Test_Smart::max() PASS : Test_Smart::cleanupTestCase() Totals: 3 passed, 0 failed, 0 skipped ********* Finished testing of Test_Smart *********
      
      







私を信じて、これは最高のテスト結果です!



しかし、まだ1つの方法をテストしていません。 私は彼に1つのテストテクニックを見せたいので、彼を去った。 私はそれを単に「 タブレット 」と呼びます。 このメソッドの本質は、コードを繰り返さないことです。 テストメソッドvoid max()を覚えていますか? そこで、同じコードを何度も繰り返しました(異なるパラメーターを使用した場合を除く)。 これを回避するために、Qtは「プレート」メソッドを実装しています。 どのように機能しますか? メソッドmethod_data()を作成し、その中でいくつかの簡単な操作を実行してから、すべてをQFETCH()マクロでロードします。 今こそ、実際にすべてを見る時です!



次は、「タブレット」の実装をtest_smart.cppに追加します



 void Test_Smart::min_data() { QTest::addColumn<int>("first"); QTest::addColumn<int>("second"); QTest::addColumn<int>("result"); QTest::newRow("min_data_1") << 1 << 0 << 0; QTest::newRow("min_data_2") << -1 << 1 << -1; QTest::newRow("min_data_3") << 4 << 8 << 4; QTest::newRow("min_data_4") << 0 << 0 << 0; QTest::newRow("min_data_5") << 1 << 1 << 1; QTest::newRow("min_data_6") << -10 << -5 << -10; } void Test_Smart::min() { Smart a; QFETCH(int, first); QFETCH(int, second); QFETCH(int, result); QCOMPARE(a.min(first, second), result); }
      
      







もう一度コンパイルします。 結論が出ました。



testing.log

 ********* Start testing of Test_Smart ********* Config: Using QTest library 4.8.1, Qt 4.8.1 PASS : Test_Smart::initTestCase() PASS : Test_Smart::max() PASS : Test_Smart::min() PASS : Test_Smart::cleanupTestCase() Totals: 4 passed, 0 failed, 0 skipped ********* Finished testing of Test_Smart *********
      
      







ここで、どこか間違ったことをします。 たとえば、Smart :: min(..)change <to>に変更します。

testing.log

 ********* Start testing of Test_Smart ********* Config: Using QTest library 4.8.1, Qt 4.8.1 PASS : Test_Smart::initTestCase() PASS : Test_Smart::max() FAIL! : Test_Smart::min(data_1) Compared values are not the same Actual (a.min(first, second)): 1 Expected (result): 0 Loc: [test_smart.cpp(41)] FAIL! : Test_Smart::min(data_1) Compared values are not the same Actual (a.min(first, second)): 1 Expected (result): -1 Loc: [test_smart.cpp(41)] FAIL! : Test_Smart::min(data_1) Compared values are not the same Actual (a.min(first, second)): 8 Expected (result): 4 Loc: [test_smart.cpp(41)] FAIL! : Test_Smart::min(data_1) Compared values are not the same Actual (a.min(first, second)): -5 Expected (result): -10 Loc: [test_smart.cpp(41)] PASS : Test_Smart::cleanupTestCase() Totals: 3 passed, 4 failed, 0 skipped ********* Finished testing of Test_Smart *********
      
      







だからすべてが良いです)。



GUIのテスト



時には、時には非常に頻繁に、グラフィカルインターフェイスをテストする必要があります。 QTestLibでは、これも実装されています。 QLineEditをテストしましょう。



これは、 test_qlineedit.hの外観です。

 #ifndef TEST_QLINEEDIT_H #define TEST_QLINEEDIT_H #include <QObject> class Test_QLineEdit : public QObject { Q_OBJECT private slots: //    void edit(); }; #endif // TEST_QLINEEDIT_H
      
      







そして、 test_qlineedit.cppもここにあります:

 #include <QtTest> #include <QtGui> #include "test_qlineedit.h" void Test_QLineEdit::edit() { QLineEdit a; QTest::keyClicks(&a, "abCDEf123-"); QCOMPARE(a.text(), QString("abCDEf123-")); QVERIFY(a.isModified()); }
      
      







main.cppを修正する時が来ました

 #include <QApplication> #include <QTest> #include <iostream> #include <cstdlib> #include <cstdio> #include "test_smart.h" #include "test_qlineedit.h" using namespace std; int main(int argc, char *argv[]) { freopen("testing.log", "w", stdout); QApplication a(argc, argv); QTest::qExec(new Test_Smart, argc, argv); cout << endl; QTest::qExec(new Test_QLineEdit, argc, argv); return 0; }
      
      







テストを開始します。

 ********* Start testing of Test_Smart ********* Config: Using QTest library 4.8.1, Qt 4.8.1 PASS : Test_Smart::initTestCase() PASS : Test_Smart::max() PASS : Test_Smart::min() PASS : Test_Smart::cleanupTestCase() Totals: 4 passed, 0 failed, 0 skipped ********* Finished testing of Test_Smart ********* ********* Start testing of Test_QLineEdit ********* Config: Using QTest library 4.8.1, Qt 4.8.1 PASS : Test_QLineEdit::initTestCase() PASS : Test_QLineEdit::edit() PASS : Test_QLineEdit::cleanupTestCase() Totals: 3 passed, 0 failed, 0 skipped ********* Finished testing of Test_QLineEdit *********
      
      







そこで、GUIをテストする方法を学びました。 テストでは、QLineEditが正しく機能していることが示されました)。



テスト引数



オプション 説明
-oファイル名 テスト結果をファイル名に出力
-サイレント メッセージを警告とエラーのみに制限する
-v1 テストメソッドの入力と出力に関する情報を表示する
-v2 QCOMPAREおよびQVERIFYマクロのメッセージを表示することにより、-v1オプションを補足します
-対 送信された各信号と呼び出されたスロットを表示する
-xml すべての情報をXML形式で出力します
-eventdelay ms テストを停止し、msミリ秒待機します。 このオプションは、GUI要素のエラーを見つけるのに役立ちます。


本日お伝えしたことは、Qtアプリケーションのテストを今すぐ開始するのに十分です。 私はあなたに何を伝えることができますか? コメントに記事を改善するためのすべてのヒントと提案を書くようお願いします-これは私にとって重要であり、これが私の最後の記事ではないことを願っています。



あなたに幸運と良いコード;)



All Articles