C++
TDD
Qt
unittest
googletest

Qtでgoogletestを使うときのテンプレート

More than 1 year has passed since last update.

はじめに

Qt Creatorでgoogletestを使えるようになりました(詳しくはQt Creator Autotest Plugin について

でも、実際に使ってみようとすると、どういうプロジェクト構成にすると、プロダクトコードとテストコードをうまく管理できるかわかりませんでした。
そこで、自分なりのテンプレートを作ってみることにしました。

もっといい方法をご存知の方は、ぜひ突っ込みをお願いします。

手順

  1. subdirsテンプレートで新規アプリケーションを作成
  2. プロダクトコードをサブプロジェクトとして取り込む
  3. プロダクトコードの.proファイルから、ソースファイルとヘッダファイルの指定を.priファイルに移す
  4. Auto Test Projectをサブプロジェクトとして作成
  5. テスト用サブプロジェクトからプロダクトコードを参照
  6. テストを書く

subdirsテンプレートで新規アプリケーションを作成

Qt Creatorでsubdirsプロジェクトを新規に作成します。
プロダクトコードのプロジェクト名と同名にならないようにだけ、気を付けます。

今回は、simplebrowser-gtestとしました。
この時点でのディレクトリ構造は、次の通りです。
simplebrowser-gtest/
└── simplebrowser-gtest.pro

simplebroser-gtest.proの中身は、次の1行だけです。
TEMPLATE = subdirs

プロダクトコードをサブプロジェクトとして取り込む

今回は、QtのExampleに含まれる、WebEngineWidgetsのsimplebrowserプロジェクトを取り込みます。
Qt Creatorでのやり方がよくわからないため、手動で行いました。
simplebrowserディレクトリを、simplebrowser-gtest配下に、がさっとコピーします。
simplebrowser-gtest/
├── simplebrowser
│   ├── browser.cpp
│   ├── browser.h
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
一部省略
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
│   ├── simplebrowser.pro
│   ├── webpopupwindow.cpp
│   ├── webpopupwindow.h
│   ├── webview.cpp
│   └── webview.h
└── simplebrowser-gtest.pro

simplebrowser-gtest.proに次の1行を追加します。
SUBDIRS = simplebrowser

これで、simplebrowserプロジェクトが、simplebroser-gtestに取り込まれます。
試しにQt CreatorのRunボタンを押すと、simplebrowserが立ち上がります。

プロダクトコードの.proファイルから、ソースファイルとヘッダファイルの指定を.priファイルに移す

simplebrowser.proは次のようになっています。
googletestでmain.cpp以外に対して、ユニットテストを書きたいです。

TEMPLATE = app
TARGET = simplebrowser
QT += webenginewidgets
CONFIG += c++11

HEADERS += \
    browser.h \
    browserwindow.h \
    downloadmanagerwidget.h \
    downloadwidget.h \
    tabwidget.h \
    webpage.h \
    webpopupwindow.h \
    webview.h

SOURCES += \
    browser.cpp \
    browserwindow.cpp \
    downloadmanagerwidget.cpp \
    downloadwidget.cpp \
    main.cpp \
    tabwidget.cpp \
    webpage.cpp \
    webpopupwindow.cpp \
    webview.cpp

FORMS += \
    certificateerrordialog.ui \
    passworddialog.ui \
    downloadmanagerwidget.ui \
    downloadwidget.ui

RESOURCES += data/simplebrowser.qrc

そこで、テスト用のサブプロジェクトとソースコードを共有できるように、ソースとヘッダファイルの指定を、proファイルからpriファイルに移します。
simplebrowser.priを次の通り作成します。テスト用のサブプロジェクトから参照できるように、インクルードパスを追加し、ソースとヘッダファイルもディレクトリパスから記載します。
main.cppは、priに書かないようにします。

SRC_DIR = $$PWD
HEAD_DIR = $$PWD
FORM_DIR = $$PWD

INCLUDEPATH *= \
    $$HEAD_DIR

HEADERS += \
    $$HEAD_DIR/browser.h \
    $$HEAD_DIR/browserwindow.h \
    $$HEAD_DIR/downloadmanagerwidget.h \
    $$HEAD_DIR/downloadwidget.h \
    $$HEAD_DIR/tabwidget.h \
    $$HEAD_DIR/webpage.h \
    $$HEAD_DIR/webpopupwindow.h \
    $$HEAD_DIR/webview.h

SOURCES += \
    $$SRC_DIR/browser.cpp \
    $$SRC_DIR/browserwindow.cpp \
    $$SRC_DIR/downloadmanagerwidget.cpp \
    $$SRC_DIR/downloadwidget.cpp \
    $$SRC_DIR/tabwidget.cpp \
    $$SRC_DIR/webpage.cpp \
    $$SRC_DIR/webpopupwindow.cpp \
    $$SRC_DIR/webview.cpp

FORMS += \
    $$FORM_DIR/certificateerrordialog.ui \
    $$FORM_DIR/passworddialog.ui \
    $$FORM_DIR/downloadmanagerwidget.ui \
    $$FORM_DIR/downloadwidget.ui

RESOURCES += $$SRC_DIR/data/simplebrowser.qrc

simplebrowser.proから、ソースとヘッダファイルの指定を取り除き、次の1行を追加して、priファイルをインクルードします。
include(simplebrowser.pri)

最終的に、simplebrowser.proは次のようになりました。(ずいぶんすっきりです)

TEMPLATE = app
TARGET = simplebrowser
QT += webenginewidgets
CONFIG += c++11
include(simplebrowser.pri)

SOURCES += \
    main.cpp

Auto Test Projectをサブプロジェクトとして作成

simplebrowser-gtest配下に、Auto Test Projectをサブプロジェクトとして作成します。
今回は、simplebrowser-unittestというプロジェクト名を付けました。
Test Frameworkにはgoogletestを選択します。
あらかじめ、googletestのレポジトリをどこかにcloneしておく必要があります。

最後のSummary画面で、Auto Test Projectが、ちゃんとターゲットのサブプロジェクトになっていることを確認します。
Add as a subproject to project: simplebrowser-gtest

テスト用サブプロジェクトからプロダクトコードを参照

先ほど作成したプロジェクトの、simplebrowser-unittest.proは、以下のようになります。

include(gtest_dependency.pri)

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG += thread
CONFIG -= qt

HEADERS +=     tst_webviewtest.h

SOURCES +=     main.cpp

以下の1行を追加して、テストしたいターゲットのソースとヘッダを参照します。
include(../simplebrowser/simplebrowser.pri)

テストを書く

テストを書きます。
力尽きてしまったので、以下のコードはとりあえず、プロダクトコードを参照して、googletestのフレームワークが動く、程度のものです。
Qt CreatorのTools->Tests->Run All Tests、で無事テストが動作し、テストがパスしました。
Qt CreatorのRunボタンを押すと、変わらず、simplebrowserが起動します。

#include <gtest/gtest.h>
#include <gmock/gmock-matchers.h>
#include "browser.h"
#include "browserwindow.h"
#include "webview.h"
#include <QApplication>

using namespace testing;

TEST(WebViewTest, Test1)
{
    int argc;
    char **argv;
    QApplication app(argc, argv);

    QUrl expected = QStringLiteral("https://www.qt.io");
    Browser browser;
    BrowserWindow *window = browser.createWindow();
    window->currentTab()->setUrl(expected);

    QUrl actual = window->currentTab()->url();

    EXPECT_EQ(expected, actual);
}

テストを書く上で、simplebrowser-unittest.proを以下の通り修正しないとダメでした。
追加:
QT += webenginewidgets
削除:
CONFIG -= qt

このあたりは、プロダクトコードのpriファイルに書いておくほうがよさそうですね。

コードはこちら
https://github.com/tomoyuki-nakabayashi/qt-googletest-template