Qt Creator Autotest Plugin について

#はじめに
今回で3回目の投稿となります、ynuma です。
驚いたことに、去年のアドベントカレンダーも 12/21 に投稿しておりました。
ちょうど一年ぶりとなりますので、近況を簡単に書かせていただきます。
普段は、相変わらずHWの仕事を中心に行っております。
SWの方は、HWの評価用に簡単なクラスを作るくらいですが、常に新しい技術を勉強していきたい、と思っています。

本題になりますが、今回のテーマは昨年に引き続き Qt Test についてです。
昨年は、主に Qt Test Unit Test Framework の基本的な使い方についてまとめました。
詳細は、前回の記事を参照ください。
http://qiita.com/ynuma/items/b728c613e003b69e23a5

今回はそれをさらに拡張した Qt Creator AutoTest Plugin の使い方についてまとめます(以下、AutoTest Plugin と略します)。


# Autotest Plugin について
簡単にいってしまうと Qt Creator 上で動作するテストの自動化を行うための管理ツールです。
自動テストというと Jenkins のようなサーバーとして動作する CI ツールを思い浮かべる方が多いのではないかと思いますが、今回ご紹介するのは、Qt Creator 上で動作する Plugin で、Qt Creator のビルド実行後に、テストを実行・管理するツールです。
初期インストール後は使用できない状態でないので、プラグインを追加する必要があります（後述）。


# 対象のバージョン
私が昨年の原稿を書いた時にインストールした Qt Creator v3.5.1 では、下図の通りプラグインの項目に Autotest が出てきません！
![スクリーンショット 2016-12-20 5.26.17.png](https://qiita-image-store.s3.amazonaws.com/0/62136/e60493c8-0e04-1326-fb47-115b8160109a.png)

この機能の存在を知ったのは、友人の @hermit4 氏から教えていただいたからで、自力ではなかなか気がつかなかったのではないかと思います。
いったい、どのバージョンから使えるのでしょうか？
ちょっと気になったので、Qt project の GitHub を調べてみました。

History for qt-creator/src/plugins/autotest の一番古い commit ログが、
2016/1/22 となっています。
この後リリースされた Qt Creator の バージョンが、v3.6.1(2016/3/16)
です。その次は、
v4.0.0-beta1(2016/3/23)
です。

3.6.1 リリース直後に Bugfix も行われているようなので、実質 4.0 以降で使えるものと思っていただければよいかと思います。


# この記事の作成に使用した Qt Creator のバージョン
この記事は、v4.1.0 を使用して記述しています。
12/14(Wed) に、v4.2.0 がリリースされていたのを投稿直前になって知りました。
非常に残念ですが、今回は時間がないので、v4.2.0 については触れません。


# 注目すべき点
昨年記事を書いた時点で、既に Qt unit test というものが提供されていました。
これは、1 つのプロジェクトという扱いで、IDE として使用するには少し物足りない感じでした。
他のプロジェクトファイルと同様にテストのソースコードをビルドして、実行するという流れでした。
複数のテストケースを実行する場合に、ユーザーがコードやプロジェクトを選択・変更してテストを実施する必要がありました。

Autotest Plugin では、Qt Creator 上に、プロジェクトとは別の "テスト" というメニューが追加されています。
具体的には、複数のテストケースを GUI から選択して実行したり、前述のような一般的な CI ツール風に使用できるようになりました。

テストのフレームワークは、Qt Test, Quick Test, Google Test を選択できます。 


# 使用するための準備
使用するためには、Qt Creator Plugin に Autotest を追加する必要があります。
メニューバーの
Qt Creator → プラグインについて
と操作すると、下図のようなインストール済みプラグインの一覧が表示されます。
このリストの中の下部にユーティリティという項目があり、その中の AutoTest を選択します。
もし、この AutoTest という項目が現れない場合は、Qt Creator を update してください。

![スクリーンショット 2016-12-19 6.30.11.png](https://qiita-image-store.s3.amazonaws.com/0/62136/5b3ae877-d351-7f82-2a1d-71e2fbbdd032.png)

この後、Qt Creator の再起動が必要です。
*見逃す可能性がありますが、一応ダイアログの下部に再起動を促すメッセージが表示されています。


# Testcase 作成方法
実際にテストケースの作り方について、説明します。
メニューバーから

ファイル → ファイル/プロジェクトの新規作成

と操作すると、下記ダイアログが表示されます。

![スクリーンショット 2016-12-20 5.35.43.png](https://qiita-image-store.s3.amazonaws.com/0/62136/0f63a0ea-cddf-c253-61bc-9165279e9781.png)

プロジェクト → 他のプロジェクト→ Auto Test Project

と選択し、選択ボタンを押します。
下図の通りプロジェクトパスの設定ダイアログが表示されます。

![スクリーンショット 2016-12-20 5.41.31.png](https://qiita-image-store.s3.amazonaws.com/0/62136/1f7055bd-56d0-180b-a2fb-66431b9c20ef.png)

プロジェクト名とパスを選択し、続きを押します。
下図の通り、Project and Test Information ダイアログが表示されます。

![スクリーンショット 2016-12-20 5.43.38.png](https://qiita-image-store.s3.amazonaws.com/0/62136/3190c9c1-95d6-dcad-57b9-2ffe3288d072.png)

お好みの設定を行います。
今回の説明では、Test Framework は Qt Test、GUI Application などのチェックボックスはすべて選択しました。
Test Case Name は何でも構いません。
Build auto tests の選択については、存在理由が理解できていないのですが、とりあえず always としておきます(アプリをビルドする度に毎回 Test が実行されると思ったのですが、そのような動作は行われませんでした)。
続きを押すと、下図の通り、キットの選択画面が表示されます。

![スクリーンショット 2016-12-20 6.16.58.png](https://qiita-image-store.s3.amazonaws.com/0/62136/01c350cc-809b-f679-c21a-bcb841813b9e.png)

今回は、このまま続きを押します。
下図の通り、プロジェクト管理画面が表示されます。

![スクリーンショット 2016-12-20 6.20.27.png](https://qiita-image-store.s3.amazonaws.com/0/62136/bb89d1d0-c883-5627-7479-7c0cb3e2c8af.png)

適宜設定して、終了を押します。
下図の通り、case11 という名前の testcase が含まれた空の Project が作成されます。

![スクリーンショット 2016-12-20 6.22.40.png](https://qiita-image-store.s3.amazonaws.com/0/62136/44b61b12-0731-1616-a066-18ba5cbb7257.png)

この後、Unit test を作るときと同様に、テストケースを記述していきます。


# testcase 実行方法

testcase が作成できたら、テストを実行します。
まずは、サイドバーにテストというメニューが追加されているので、そちらを表示してみましょう。

![pict1.png](https://qiita-image-store.s3.amazonaws.com/0/62136/24e91732-d9d5-d455-6ea1-b2b1a78aff0a.png)


↓
![スクリーンショット 2016-12-20 6.29.51.png](https://qiita-image-store.s3.amazonaws.com/0/62136/f60750d2-a3a4-f736-2594-4a50e75130fe.png)

このような感じで、一般の IDE 風にテストケースの選択画面が出てきます。
下図のように、サイドバーの上段にプロジェクト、下段にテストというレイアウトが作業しやすいかと思います。サイドバーに複数の画面を表示させるには、サイドバーのアイコンの ![スクリーンショット 2016-12-20 6.46.14.png](https://qiita-image-store.s3.amazonaws.com/0/62136/35378d7c-1e86-39af-02ab-e2961666d06c.png) ボタンを押します。

![スクリーンショット 2016-12-20 6.47.56.png](https://qiita-image-store.s3.amazonaws.com/0/62136/2afe581b-a40a-a053-c338-9ac87edd7ce6.png)


テストケースを選択して、Qt Test の箇所を右クリックし、選択したテストの実行をクリックすれば、必要なテストだけ選択実行できます。
もちろん、すべてのテストの実行も選択できます。

![pict2.png](https://qiita-image-store.s3.amazonaws.com/0/62136/938fc4de-1902-ba9c-2103-428a509623a4.png)


# 実行結果について

先ほどの画面の右下の部分にアプリケーション出力が表示されています。
ここには、Unit Test の結果が表示されます。
この他に、Window 下部の
８ テスト結果
を選択すると、IDE 風に欠ケース毎の Pass/Fail 結果のみが表示されます。

![スクリーンショット 2016-12-20 6.41.31.png](https://qiita-image-store.s3.amazonaws.com/0/62136/adc7680c-a179-33e3-219b-2a214a89fbc4.png)


# その他の設定について

メニューバーの Qt Creator → 設定... と選択すると、以下のような各種設定 Diaglog が表示されます。

![スクリーンショット 2016-12-20 20.38.18.png](https://qiita-image-store.s3.amazonaws.com/0/62136/d72cfe37-89d3-9745-2e6f-72face1ab583.png)

左側のメニューリストから、”QAテスト設定” という項目を選択すると、Autotest に関する詳細設定を行うことが可能です。

例えば、結果の出力を制限するとか、テストのフレームワークを表示させないようにすることができるようです。
また、ここでベンチマーク測定機能の設定も行えるようです。
経過時間だけでなく、ティックカウンタ（組み込み向け？）やイベントカウンタなど、かなり凝った測定も行えるようになっているようです。

加えて、Google Test の設定も変えられるようです。

こういった細々した内容の設定をマニュアルでやる場合は、深い知識と時間が要求されますが、このように UI から簡単に選択できるようになったのは、大変便利になったのではないか、と思います。


# UIアプリテスト例

実際に簡単なUIアプリケーションのテストを書いてみました。
アプリケーションは、下記コードの通り、MainWindow に3つの sinewave を表示する単純なものです。

![スクリーンショット 2016-12-20 20.33.09.png](https://qiita-image-store.s3.amazonaws.com/0/62136/28d62022-cd9a-bd06-2771-2fc16d2c5481.png)


```cpp:mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    double calcRadian(const int x, const int points);
    int showSineWave(const int waves, const int xStart, const int xStop, const int yTop, const int yOffset);

protected:
    void paintEvent(QPaintEvent *);

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
```

```cpp:mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPainter>
#include <math.h>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

double
MainWindow::calcRadian(const int x, const int points)
{
    const double Pi = 3.14;
    return double(2 * Pi * (x % points) / (points - 1));
}

int
MainWindow::showSineWave(const int waves, const int xStart, const int xStop, const int yTop, const int yOffset)
{
    if (waves < 0 || xStart < 0 || xStop < 0 || yTop < 0 || yOffset < 0)
    {
        return -1;
    }

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setPen(QPen(Qt::red, 8, Qt::SolidLine, Qt::RoundCap));

    const int pointsPerWave = (xStop - xStart) / waves;
    for (int x = xStart; x <= xStop; ++x)
    {
        int y = yTop * sin(calcRadian(x, pointsPerWave)) + yOffset;
        painter.drawPoint(x, y);
    }

    return 0;
}

void
MainWindow::paintEvent(QPaintEvent *)
{
    showSineWave(1, 100, 700, 75, 100);
    showSineWave(2, 100, 700, 70, 300);
    showSineWave(4, 100, 700, 65, 500);
}

MainWindow::~MainWindow()
{
    delete ui;
}
```


■ テストコード

このテストコードは、MainWindow Class の public method の unit test case です。
また、UI の目視確認ができるように Window をわざと表示させています。
最初の思惑としては、画面のスクリーンショットを期待値として、画像を比較チェックするつもりでしたが、あまり凝ってもわかりにくくなるので、今回はそこまでしません。


```cpp:tst_case1.cpp

#include <QtTest>
#include <QCoreApplication>

// add necessary includes here
#include "/Users/ynumajir/WidgetApp/autotest/src/mainwindow.h"
#include <unistd.h>

class case1 : public QObject
{
    Q_OBJECT

public:
    case1();
    ~case1();

private slots:
    void initTestCase();
    void cleanupTestCase();
    void test_case1();

};

case1::case1()
{

}

case1::~case1()
{

}

void case1::initTestCase()
{

}

void case1::cleanupTestCase()
{

}

void case1::test_case1()
{
    MainWindow mainWin;
    mainWin.show();
    sleep(1);
    QVERIFY(-1 == mainWin.showSineWave(-1, -1, -1, -1, -1));
    QVERIFY(0 == mainWin.calcRadian(0, 201));
    QVERIFY(3.14 == mainWin.calcRadian(100, 201));
}

QTEST_MAIN(case1)

#include "tst_case1.moc"
```


テストを実行すると、すべて Pass します。
もし興味がありましたら、実行してみてください。


# 参考リンク
- Qt Creator Autotest Documentation:
  http://doc.qt.io/qtcreator/creator-autotest.html
- Qt Documentation:
  http://doc.qt.io/qt-5/qtest-overview.html
- Google Test:
  https://github.com/google/googletest