Qt (10) QTestLibで簡単なテストを行う
公開日| 2009年06月27日 | コメントはまだありません。
カテゴリー:Qt |
概要 : Qtでは、CppUnitのようなQTestLibがあります。
今回の記事では、QTestLib簡単なテスト実行プログラムを作成してみましょう。
(この記事は、関連記事サイトのチュートリアルの一部です。Qtの初心者向けプログラマーをターゲットに記載されています。)
関連記事: http://doc.trolltech.com/4.5.1/qtestlib-manual.html
ここで使用したサンプルソースコード:
簡単なテストターゲットクラスを作る
今回のために、簡単なテストターゲット用の独自のクラスを用意してみました。[TestPlus.h]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class CTestPlus { public : CTestPlus(); virtual ~CTestPlus(); // calc method int plus(int val); int minus(int val); // value method int value(); void value(int val); private : int m_value[3]; }; |
[TestPlus.cpp]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include "TestPlus.h" CTestPlus::CTestPlus() { for(int ni=0;ni<3;ni++) m_value[ni]=0; } CTestPlus::~CTestPlus() { } int CTestPlus::plus(int val) { m_value[0]=m_value[2]; m_value[1]=val; m_value[2]=m_value[0]+m_value[1]; return value(); } int CTestPlus::minus(int val) { m_value[0]=m_value[2]; m_value[1]=val; m_value[2]=m_value[0]-m_value[1]; return value(); } int CTestPlus::value() { return m_value[2]; } void CTestPlus::value(int val) { m_value[2]=val; } |
すごく単純なクラスです。
テストを行いたいメソッドは、以下の2つのメソッドです。
- int plus(int val);
- 現在の値に指定のval値を足しこみます。 - int minus(int val);
- 現在の値に指定のval値を減らします。
どんな計算をしたかをスタック上でも確認できるように 内部の値は、配列で持っています。
では、テストプログラムを以下のようにしてみました。
[sample.cpp]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include "TestPlus.h" #include <QtTest/QtTest> class TestCTestPlus: public QObject { Q_OBJECT private slots: void testMinus_data(); void testPlus(); void testMinus(); }; void TestCTestPlus::testPlus() { CTestPlus sobj; QBENCHMARK { sobj.value(3); sobj.plus(4); } QCOMPARE(sobj.value(), int(7)); } void TestCTestPlus::testMinus_data() { QTest::addColumn<int>("value"); QTest::addColumn<int>("minus"); QTest::addColumn<int>("result"); QTest::newRow("3-4") << 3 << 4 << -1; QTest::newRow("-1+5") << -1 << -5 << 4; QTest::newRow("-1+4") << -1 << -4 << 5; // error QTest::newRow("4-3") << 4 << 3 << 1; } void TestCTestPlus::testMinus() { QFETCH(int, value); QFETCH(int, minus); QFETCH(int, result); CTestPlus sobj; sobj.value(value); QCOMPARE(sobj.minus(minus), result); } QTEST_MAIN(TestCTestPlus) #include "sample.moc" |
簡単に解説しておきます。
まず、最初、最後に決まりごととして以下の件があります。
5行目、テスト用クラスは、必ず、QObjectを継承します。
50行目、テスト用クラスは、必ず、QTEST_MAINマクロを使用してmainプログラムを作成します。
51行目、テスト用クラスは、必ず、自身のmocを最後にincludeします。
QTEST_MAINに関しては、独自に作成することもできます。ただ、上記のやり方を踏襲した方が簡単なので、そのように記述しています。
テスト用のメソッドは、private slotsで定義します。
名前は、何でも良いですが、わかりやすい名前が良いでしょう。
15行目からは、plusメソッドのテストを行っています。
18行目は、ベンチマークテストの設定例です。QBENCHMARK()マクロで指定した範囲の処理能力テストを行うことができます。 デフォルトのテスト動作は、処理時間です。処理時間以外にも、ベンチマークテストのパラメータを指定することで、CPU CLOCKなどの情報を 出力させることもできます。
22行目は、比較しています。
QCOMPAREマクロでは、第一引数と第二引数が一致していればテストOKとなります。
第一引数と第二引数には、比較演算子(==)が使えるものは、全て設定できます。
例えば、CTestPlusに
-
bool operator==( const CTestPlus& _Right ) const;
25行目は、テストメソッド(testMinus)のデータ設定メソッドです。
テスト用メソッド名_data()は、テスト用メソッドのためのデータ設定メソッドとして予約名となります。
データ設定は、以下の設定を行う必要があります。
- QTest::addColumn
テンプレートを使って、テスト用メソッドで使用するパラメータの型と名前を定義します。 - QTest::newRow(name)を使って、テスト用データのパターン名とパラメータを定義します。
37行目からが、先に設定されたデストパラメータを取り出して、テストを実施するメソッドになります。
QFETCHマクロで、順次、データ設定されているパラメータを型、名前を指定して取り出します。
44行目から、取り出したパラメータを使ってテストを実行しているところです。
先に設定されているテストパターン毎に、このメソッドがコールされますので、ここでテストパターンの数などを意識する必要はありません。
あまり独自で何か特別なことをやらない限りは、非常に簡単です。
テストを行いましょう
では、早速、このテストプログラムをコンパイルして実行してみましょう。
コンパイル時は、以下のようにコマンドパラメータでQTHELPを取り込むか、.proへ追記する必要があります。
.proへ追記する場合は、以下の1行を追加します。
QT += testlib
> qmake "QT+=testlib"
.proへ追記する場合は、以下の1行を追加します。
QT += testlib
このテストプログラムを実行すると、以下のような結果が表示されます。
ちゃんと、33行目のテストパターンについては、"FAIL(失敗)"となっています。
>testnew.exe
********* Start testing of TestCTestPlus *********
Config: Using QTest library 4.5.1, Qt 4.5.1
PASS : TestCTestPlus::initTestCase()
RESULT : TestCTestPlus::testPlus():
0.000044 msec per iteration (total: 47, iterations: 1048576)
PASS : TestCTestPlus::testPlus()
FAIL! : TestCTestPlus::testMinus(-1+4) Compared values are not the same
Actual (sobj.minus(minus)): 3
Expected (result): 5
.\sample.cpp(47) : failure location
PASS : TestCTestPlus::cleanupTestCase()
Totals: 3 passed, 1 failed, 0 skipped
********* Finished testing of TestCTestPlus *********
>testnew.exe testPlus
********* Start testing of TestCTestPlus *********
Config: Using QTest library 4.5.1, Qt 4.5.1
PASS : TestCTestPlus::initTestCase()
RESULT : TestCTestPlus::testPlus():
0.000044 msec per iteration (total: 47, iterations: 1048576)
PASS : TestCTestPlus::testPlus()
PASS : TestCTestPlus::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped
********* Finished testing of TestCTestPlus *********
>testnew.exe testMinus:-1+4
********* Start testing of TestCTestPlus *********
Config: Using QTest library 4.5.1, Qt 4.5.1
PASS : TestCTestPlus::initTestCase()
FAIL! : TestCTestPlus::testMinus(-1+4) Compared values are not the same
Actual (sobj.minus(minus)): 3
Expected (result): 5
.\sample.cpp(47) : failure location
PASS : TestCTestPlus::cleanupTestCase()
Totals: 2 passed, 1 failed, 0 skipped
********* Finished testing of TestCTestPlus *********
>testnew.exe testMinus:-1+5
********* Start testing of TestCTestPlus *********
Config: Using QTest library 4.5.1, Qt 4.5.1
PASS : TestCTestPlus::initTestCase()
PASS : TestCTestPlus::testMinus()
PASS : TestCTestPlus::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped
********* Finished testing of TestCTestPlus *********
>testnew.exe testPlus -tickcounter
********* Start testing of TestCTestPlus *********
Config: Using QTest library 4.5.1, Qt 4.5.1
PASS : TestCTestPlus::initTestCase()
RESULT : TestCTestPlus::testPlus():
664 ticks per iteration (total: 664, iterations: 1)
PASS : TestCTestPlus::testPlus()
PASS : TestCTestPlus::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped
********* Finished testing of TestCTestPlus *********
すごく簡単なのですが、QTestLibの主な機能が、ここに、(GUIのテスト部分がありませんが)ほとんど記載されています。
入力パターンを変えているのは、このテスト用実行プログラムには、様々なパラメータを指定することができるので、その一例として 上記のパターンでテストをしてみました。
(パラメータの詳細は、以降参照)
テストプログラムには、自動的に以下のパラメータを指定できるようになります。
-
testname [options] [testfunctions[:testdata]]...
- -help
outputs the possible command line arguments and give some useful help.
- -functions
outputs all test functions available in the test.
- -o filename
write output to the specified file, rather than to standard output
- -silent
silent output, only shows warnings, failures and minimal status messages
- -v1
verbose output; outputs information on entering and exiting test functions.
- -v2
extended verbose output; also outputs each QCOMPARE() and QVERIFY()
- -vs
outputs every signal that gets emitted
- -xml
outputs XML formatted results instead of plain text
- -lightxml
outputs results as a stream of XML tags
- -eventdelay ms
if no delay is specified for keyboard or mouse simulation (QTest::keyClick(), QTest::mouseClick() etc.), the value from this parameter (in milliseconds) is substituted.
- -keydelay ms
like -eventdelay, but only influences keyboard simulation and not mouse simulation.
- -mousedelay ms
like -eventdelay, but only influences mouse simulation and not keyboard simulation.
- -keyevent-verbose
output more verbose output for keyboard simulation
- -maxwarnings numberBR sets the maximum number of warnings to output. 0 for unlimited, defaults to 2000.
[options]は、以降を参照のこと。
[testfunctions[:testdata]]
一部のテストメソッドのみ実行したい場合に指定します。下記の形式で指定します。
メソッド名:テストパターン名
※テストパターン名が入力されない場合は、指定されたメソッドの全てのパターンがテストされます。
また、ベンチマークテストでは、更に以下のようなパラメータを指定することができます。
- Walltime (default) All platforms
- CPU tick counter -tickcounter Windows, Mac OS X, Linux, many UNIX-like systems.
- Valgrind/Callgrind -callgrind Linux (if installed)
- Event Counter -eventcounter All platforms
簡単な画面テストの例
以下は、チュートリアルにある画面のテスト例です。あえて、チュートリアルにあるものを解説いたしません。
[sample.cpp]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <QtGui> #include <QtTest/QtTest> class TestKeyType: public QObject { Q_OBJECT private slots: void testKeyInput(); }; void TestKeyType::testKeyInput() { QLineEdit lineEdit; QTest::keyClicks(&lineEdit, "hello world"); QCOMPARE(lineEdit.text(), QString("hello world")); QTest::keyClicks(&lineEdit, "hello worlD2"); QCOMPARE(lineEdit.text(), QString("hello world2")); } QTEST_MAIN(TestKeyType) #include "sample.moc" |
[実行結果]
********* Start testing of TestKeyType *********
Config: Using QTest library 4.5.1, Qt 4.5.1
PASS : TestKeyType::initTestCase()
FAIL! : TestKeyType::testKeyInput() Compared values are not the same
Actual (lineEdit.text()): hello worldhello worlD2
Expected (QString("hello world2")): hello world2
.\sample.cpp(20) : failure location
PASS : TestKeyType::cleanupTestCase()
Totals: 2 passed, 1 failed, 0 skipped
********* Finished testing of TestKeyType *********
上記では、keyClicksを使用していますが、他にも以下のものが使えます。
- QTest::keyClicks()
- QTest::keyClick()
- QTest::keyPress()
- QTest::keyRelease()
- QTest::mouseClick()
- QTest::mouseDClick()
- QTest::mouseMove()
- QTest::mousePress()
- QTest::mouseRelease()
[sample.cpp]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #include <QtGui> #include <QtTest/QtTest> class TestKeyType: public QObject { Q_OBJECT private slots: void testKeyInput_data(); void testKeyInput(); }; void TestKeyType::testKeyInput_data() { QTest::addColumn<QTestEventList>("events"); QTest::addColumn<QString>("expected"); QTestEventList list1; list1.addKeyClick('a'); QTest::newRow("char") << list1 << "a"; QTestEventList list2; list2.addKeyClick('a'); list2.addKeyClick(Qt::Key_Backspace); list2.addKeyClick(Qt::Key_Backspace); list2.addKeyClick(Qt::Key_Backspace); list2.addKeyClick(Qt::Key_Backspace); QTest::newRow("there and back again") << list2 << ""; QTestEventList list3; list3.addKeyClick('a'); list3.addKeyClick('b'); list3.addKeyClick('c'); list3.addKeyClick('d'); QTest::newRow("char") << list3 << "a"; } void TestKeyType::testKeyInput() { QFETCH(QTestEventList, events); QFETCH(QString, expected); QLineEdit lineEdit; events.simulate(&lineEdit); QCOMPARE(lineEdit.text(), expected); } QTEST_MAIN(TestKeyType) #include "sample.moc" |
[実行結果]
********* Start testing of TestKeyType ********* Config: Using QTest library 4.5.1, Qt 4.5.1 PASS : TestKeyType::initTestCase() FAIL! : TestKeyType::testKeyInput(char) Compared values are not the same Actual (lineEdit.text()): abcd Expected (expected): a .\sample.cpp(48) : failure location PASS : TestKeyType::cleanupTestCase() Totals: 2 passed, 1 failed, 0 skipped ********* Finished testing of TestKeyType *********
一応、一通りのテストに関する事項を記載してみました。CppUnitよりは、簡単に記述できると思います。
また、画面もある程度は、テストの自動化ができます。
アルゴリズムのテストや、処理能力のテストなどには、非常に便利だろうと思います。
ただ、画面のテストの自動化は、なかなか、難しいというのが、個人的な感想です。
ご意見などありましたら、コメントいただけますようお願い致します。
また、画面もある程度は、テストの自動化ができます。
アルゴリズムのテストや、処理能力のテストなどには、非常に便利だろうと思います。
ただ、画面のテストの自動化は、なかなか、難しいというのが、個人的な感想です。
ご意見などありましたら、コメントいただけますようお願い致します。
もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。
![]() 入門 Qt 4 プログラミング | ![]() Qtプログラミング入門―使いやすいフレームワークを基礎から解説 (I・O BOOKS) | ![]() 24時間集中講座 Qtプログラミング | ![]() Qtプログラミング入門 | ![]() Qt GUIプログラミング (C magazine) |






