このページでは

Qt Test ベストプラクティス

バグ修正や新機能の追加の際には、Qt Testを追加することを推奨します。バグを修正する前に、修正前には失敗してバグを再現し、修正後には成功する回帰テスト(できれば自動テスト)を追加してください。新機能を開発する際には、意図した通りに動作することを検証するためのテストを追加してください。

一連のコーディング標準に準拠することで、Qt Testの自動テストがすべての環境で確実に動作する可能性が高まります。たとえば、一部のテストではディスクからデータを読み込む必要があります。この処理方法に関する標準が設定されていない場合、一部のテストは移植性が失われてしまいます。 例えば、テストデータファイルが現在の作業ディレクトリにあることを前提とするテストは、ソース内ビルドでのみ動作します。シャドウビルド(ソースディレクトリ外)では、そのテストはデータを見つけられず、失敗してしまいます。

以下のセクションでは、Qt Test を作成するためのガイドラインを説明します:

「セキュリティに関する考慮事項」のアドバイスは、これらのベストプラクティスと併せて留意する必要があります。

一般的な原則

以下のセクションでは、ユニットテストを作成するための一般的なガイドラインを説明します。

テストの検証

修正や新機能とともに、テストを記述し、新しいブランチにコミットします。 作業が完了したら、作業のベースとなっているブランチをチェックアウトし、新しいテスト用のテストファイルをこのブランチにチェックインします。これにより、以前のブランチでテストが実際に失敗することを確認でき、テストがバグを確実に検出しているか、あるいは新機能を正しくテストしているかを確認できます。

たとえば、Gitバージョン管理システムを使用する場合、QDateTime クラスのバグを修正するワークフローは以下のようになります。

  1. 修正とテスト用のブランチを作成します:git checkout -b fix-branch dev
  2. テストを作成し、バグを修正します。
  3. 修正と新しいテストの両方を組み込んでビルドおよびテストを行い、修正を適用した状態で新しいテストが成功することを確認します。
  4. 修正とテストをブランチに追加します:git add tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp src/corelib/time/qdatetime.cpp
  5. 修正内容とテストをブランチにコミットします:git commit -m 'Fix bug in QDateTime'
  6. 修正が必要だった問題をテストが実際に検出していることを確認するには、自身のブランチのベースとしたブランチをチェックアウトします:git checkout dev
  7. 修正ブランチからテストファイルのみをチェックアウトします:git checkout fix-branch -- tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp

    ソースツリーの残りの部分は dev に残り、修正は含まれていませんが、新しいテストを実行できる状態になっています。

  8. ビルドしてテストを実行し、devブランチでテストが失敗することを確認します。これにより、実際にバグが検出されていることがわかります。
  9. これで、修正ブランチに戻ることができます:git checkout fix-branch
  10. あるいは、作業ツリーを dev ブランチのクリーンな状態に復元することもできます:git checkout HEAD -- tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp

変更内容をレビューする際は、このワークフローを応用して、その変更が実際に修正対象の問題に対するテストを伴っているかどうかを確認できます。

テスト関数には説明的な名前を付ける

テストケースの命名は重要です。テスト名はそのテスト実行の失敗レポートに表示されます。データ駆動型テストの場合、データ行の名前も失敗レポートに表示されます。適切な名前を付けることで、レポートを読む人が何が問題だったのかを直感的に把握できるようになります。

テスト関数の名前は、その関数が何をテストしようとしているのかが一目瞭然であるべきです。バグ追跡システムの識別子をそのまま使用しないでください。バグ追跡システムが置き換えられた場合、識別子は無効になってしまうからです。 また、オフラインで作業している開発者はバグトラッカーにアクセスできない場合があり、一部のバグトラッカーはすべてのユーザーが利用できないこともあります。バグレポートが、将来テストコードを読む人にとって参考になる可能性がある場合は、テストの関連する部分の横にコメントとして記載しておくとよいでしょう。

同様に、データ駆動型テストを作成する際は、各テストケースが機能のどの側面に焦点を当てているかを示す、説明的な名前を付けましょう。 単にテストケースに番号を振るだけ、あるいはバグトラッカーの識別子を使用するのは避けてください。テストの出力を読む人は、その番号や識別子が何を意味するのか全く分からないでしょう。必要に応じて、テスト行にバグトラッカーの識別子を記載したコメントを追加することができます。 スペース文字や、テストを実行するコマンドラインシェルにおいて意味を持つ可能性のある文字は避けるのが最善です。これにより、テストプログラムへのコマンドラインでのテスト指定やタグ付けが容易になります。例えば、テスト実行を特定の1つのテストケースのみに限定する場合などです。

自己完結型のテスト関数を記述する

テストプログラム内では、各テスト関数は互いに独立している必要があり、以前に実行されたテスト関数に依存してはいけません。 これを確認するには、tst_foo testname を使用して、テスト関数を単独で実行します。データ駆動型テストについても同様に、テストのデータテーブルの行間の依存関係を避け、tst_foo function:tag を使用して単一の行を独立して実行できるようにしてください(たとえば、失敗の原因を調査する場合など)。

テスト対象のクラスのインスタンスを複数のテストで再利用しないでください。テスト用インスタンス(ウィジェットなど)は、テストクラスのメンバ変数として保持すべきではなく、テストが失敗した場合でも適切にクリーンアップされるよう、スタック上でインスタンス化することが望ましいです。これにより、テスト同士が互いに干渉することを防げます。

テストでグローバルな変更を行う場合は、テストが成功するか失敗するかに関わらず、テスト終了時に以前の状態が復元されるよう注意してください。テストが失敗すると、そのチェック以降のコードが実行されなくなるため、テスト終了時の復元はテストが失敗した場合には機能しません。 失敗時でも確実に状態を復元する堅牢な方法は、デストラクタによって以前の状態を復元する RAII(リソースの取得は初期化である)オブジェクトをインスタンス化することです。これは多くの場合、qScopeGuard() を使用することで便利に行うことができます。例えば

const auto restoreDefaultLocale = qScopeGuard([prior = QLocale()]() {
    QLocale::setDefault(prior);
});

テスト対象のコードが使用するロケールを制御する必要があるテストでは、QLocale::setDefault() を最初に呼び出す前に、次のように記述します。

外部への依存を避ける

テスト関数も同様に、外部リソースへの依存を避けるべきです。そのような依存関係があると、そのリソースが一時的に利用できない場合にテストが失敗しやすくなります。利用可能であっても、リソース側がテストシステムからのアクセスをブロックする可能性があります。例えば、テストが頻繁に実行されると、リソース側はテストを自身のサービスに対する望ましくない負荷と解釈するかもしれません。

アクセスできない場合にテストをスキップすると、テストを実行していれば明らかになっていたはずの問題が見過ごされてしまう可能性があり、こうした問題に対する適切な解決策とは言えません。テストの目的上必要な特性を十分に備えた、リソースのローカルな模擬環境を構築する方が望ましいです。

外部依存関係は、オフラインで作業する開発者にとって問題となるだけでなく、信頼できないソースからのコード変更を評価する際、隔離された仮想マシンなどのサンドボックス内でのテストにおいても問題を引き起こします。関連する懸念事項については、「Qt Test のセキュリティ上の考慮事項」を参照してください。

フルスタックをテストする

APIが、主要な処理を担うプラグイン式またはプラットフォーム固有のバックエンドによって実装されている場合は、バックエンドに至るまでのすべてのコードパスを網羅するテストを必ず作成してください。 モックバックエンドを使用して上位層のAPI部分をテストすることは、API層のエラーをバックエンドから切り離すための有効な方法ですが、これは、実環境の状況を忠実に再現したデータを用いて実際の実装を実行するテストを補完するものです。

テストを迅速に完了させる

テストは、不必要な繰り返し、不適切に大量のテストデータの使用、あるいは不必要なアイドル時間の発生によって、時間を浪費してはなりません。

これは特にユニットテストに当てはまります。ユニットテストの実行時間が1秒でも長くなると、複数のターゲットにわたるブランチのCIテストに時間がかかることになるからです。ユニットテストは、大量のテストデータや長時間のテスト実行が想定される負荷テストや信頼性テストとは別物であることを覚えておいてください。

通常、同じテストを複数回実行するベンチマークテストは、tests/benchmarks ディレクトリに配置し、機能的なユニットテストと混在させないようにする必要があります。

データ駆動型テストを活用する

データ駆動型テストを利用することで、後日のバグ報告で発見された境界条件に対する新しいテストを容易に追加できます。

テスト内で複数の項目を順番にテストするのではなく、データ駆動型テストを使用することで、非常に類似したコードの繰り返しを回避でき、先行するテストが失敗した場合でも、後続のケースが確実にテストされます。また、各データサンプルに対して同じテストが適用されるため、体系的かつ統一的なテストが促進されます。

テストがデータ駆動型の場合、テスト関数名とともにデータタグをfunction:tag のように指定することで、その関数のすべてのテストケースではなく、特定の 1 つのテストケースのみを実行することができます。 これは、グローバルデータタグまたはローカルタグのいずれにも使用でき、関数自身のデータから行を特定します。function:global:local のように、これらを組み合わせることも可能です。

カバレッジツールの活用

Cocoやgcovなどのカバレッジツールを使用して、テスト対象の関数やクラス内のステートメント、分岐、条件を可能な限り網羅するテストを作成しましょう。新機能の開発サイクルにおいて、この作業を早い段階で実施すればするほど、後でコードをリファクタリングした際にリグレッションを検出しやすくなります。

テストを除外するための適切な仕組みの選択

適用不可能なテストを除外するための適切なメカニズムを選択することが重要です。

QSKIP() を使用すると、実行時にテスト関数全体が現在のテスト環境では適用不可であると判断されたケースを処理できます。テスト関数の一部のみをスキップする場合は、条件分岐を使用できます。必要に応じて、qDebug() を呼び出して、適用不可な部分をスキップした理由を報告することもできます。

最終的に修正されるべき既知のテスト失敗がある場合は、QEXPECT_FAIL の使用が推奨されます。これは、可能であればテストの残りの部分を実行できるためです。また、この機能は問題が依然として存在することを検証し、コードのメンテナーが意図せず問題を修正してしまった場合にその旨を知らせることもできます。これは、Abort フラグを使用する場合でも得られる利点です。

#if を使用すると、データ駆動型テストのテスト関数やデータ行を、特定のプラットフォームや、有効化されている特定の機能に限定することができます。ただし、#if を使用してテスト関数をスキップする際は、mocの制限に注意してください。moc プリプロセッサは、コンパイラの機能検出によく使用されるbuiltin マクロのすべてにアクセスできるわけではありません。 そのため、moc によるプリプロセッサ条件の判定結果は、コードの他の部分で得られる結果とは異なる場合があります。これにより、moc が、実際のコンパイラによってスキップされるテストスロットのメタデータを生成したり、実際にはクラスにコンパイルされているテストスロットのメタデータを省略したりする可能性があります。 前者の場合、テストは実装されていないスロットを実行しようとします。後者の場合、テストは実行すべきであるにもかかわらず、テストスロットの実行を試みません。

特定のプラットフォームでは、あるいは特定の機能が有効になっていない限り、テストプログラム全体が適用できない場合、そのテストのビルドを回避するには、親ディレクトリのビルド設定を使用するのが最善の方法です。たとえば、tests/auto/gui/someclass テストが macOS では有効でない場合、tests/auto/gui/CMakeLists.txt 内のサブディレクトリとしてのそのテストのインクルードを、プラットフォームチェックで囲みます:

if(NOT APPLE)
    add_subdirectory(someclass)
endif

あるいは、qmake を使用している場合は、tests/auto/gui.pro に次の行を追加します:

mac*: SUBDIRS -= someclass

「QSKIP によるテストのスキップ」も参照してください。

Q_ASSERT の使用は避ける

Q_ASSERT マクロは、アサートされた条件がfalse である場合にプログラムをアボートさせますが、これはソフトウェアがデバッグモードでビルドされた場合に限られます。リリースビルドおよびデバッグ・リリース両方のビルドにおいて、Q_ASSERT は何もしません。

Q_ASSERT は、デバッグビルドがテストされているかどうかに応じてテストの挙動が変わってしまうこと、またテストが即座に中止され、残りのテスト関数がすべてスキップされ、不完全または不正な形式のテスト結果が返されてしまうため、避けるべきです。

また、テストの終了時に実行されるはずだったテアダウンやクリーンアップもスキップされるため、ワークスペースが整理されていない状態のまま残され、その後のテストに支障をきたす可能性があります。

Q_ASSERT の代わりに、QCOMPARE() またはQVERIFY() マクロのバリエーションを使用すべきです。これらを使用すると、現在のテストは失敗として報告され終了しますが、残りのテスト関数は実行され、テストプログラム全体は正常に終了します。QVERIFY2() を使用すると、テストログに説明的なエラーメッセージを記録することさえ可能です。

信頼性の高いテストの作成

以下のセクションでは、信頼性の高いテストを作成するためのガイドラインを説明します。

検証ステップにおける副作用の回避

QCOMPARE() やQVERIFY() などを使用して自動テストで検証ステップを実行する際は、副作用を避けるべきです。 検証ステップにおける副作用は、テストの理解を困難にする可能性があります。また、テストをQTRY_VERIFY()、QTRY_COMPARE()、またはQBENCHMARK を使用するように変更した際、診断が困難な形でテストが簡単に破綻してしまう原因にもなります。これらは渡された式を繰り返し実行するため、副作用も繰り返し発生することになります。

副作用が避けられない場合は、たとえテストが失敗したとしても、テスト関数の終了時に以前の状態が復元されるようにしてください。これには通常、RAIIクラス(上記の「自己完結型のテスト関数の作成」を参照)またはcleanup() メソッドの使用が必要となります。 単にテストの最後に復元コードを記述してはいけません。テストの一部が失敗した場合、そのコードはスキップされ、以前の状態が復元されなくなります。

固定タイムアウトは避ける

QTest::qWait() など、特定の条件が真になるのを待つためのハードコーディングされたタイムアウトの使用は避けてください。QSignalSpy クラス、QTRY_VERIFY() またはQTRY_COMPARE() マクロ、あるいはQSignalSpy クラスを、QTRY_ マクロのバリエーションと組み合わせて使用することを検討してください。

qWait() 関数を使用すると、何らかのアクションを実行してから、そのアクションによってトリガーされた非同期動作が完了するのを待つまでの間に、一定期間の遅延を設定できます。例えば、ウィジェットの状態を変更した後、ウィジェットが再描画されるのを待つ場合などです。 しかし、ワークステーション上で作成されたテストをデバイス上で実行すると、期待される動作の完了に時間がかかる場合があり、このようなタイムアウト設定が失敗の原因となることがよくあります。最も処理が遅いテストプラットフォームで必要とされる値の数倍に固定タイムアウトを延長することは、特にテーブル駆動型テストにおいて、すべてのプラットフォームでのテスト実行を遅くしてしまうため、適切な解決策とは言えません。

テスト対象のコードが非同期動作の完了時にQtシグナルを発行する場合、QSignalSpy クラスを使用して、検証ステップを実行できる状態になったことをテスト関数に通知する方が適切なアプローチです。

Qtシグナルがない場合は、QTRY_COMPARE() およびQTRY_VERIFY() マクロを使用してください。これらは、指定された条件が真になるか、最大タイムアウトに達するまで、定期的にその条件をテストします。これらのマクロは、テストが不必要に長引くのを防ぐと同時に、高速なシステムでテストを開発し、後で低速なシステムで実行する際の不具合を回避します。

Qtシグナルがなく、新しいAPIの開発の一環としてテストを作成している場合は、非同期動作の完了を通知するシグナルを追加することでAPIが改善されるかどうかを検討してください。テストが容易になるのであれば、APIの呼び出し元にとっても有用である可能性が高いでしょう。

タイミング依存の挙動に注意

一部のテスト戦略は、特定のクラスのタイミング依存の挙動の影響を受けやすく、その結果、特定のプラットフォームでのみテストが失敗したり、一貫性のない結果が返されたりすることがあります。

その一例として、テキスト入力ウィジェットが挙げられます。これらはしばしばカーソルが点滅しており、ビットマップのキャプチャ時にカーソルの状態によって、キャプチャされたビットマップの比較が成功したり失敗したりすることがあります。これは、テストを実行するマシンの速度に依存する場合もあります。

タイマーイベントに基づいて状態が変化するクラスをテストする場合、検証手順を実行する際には、タイマーに基づく挙動を考慮に入れる必要があります。タイミング依存の挙動には様々な種類があるため、このテスト問題に対する単一の汎用的な解決策は存在しません。

テキスト入力ウィジェットの場合、考えられる解決策としては、カーソルの点滅動作を無効にする(API がその機能を提供している場合)、ビットマップをキャプチャする前にカーソルが既知の状態になるのを待つ (たとえば、API が適切なシグナルを提供している場合は、そのシグナルをサブスクライブする)、あるいはビットマップの比較からカーソルを含む領域を除外することなどが考えられます。

ビットマップのキャプチャと比較は避ける

ビットマップのキャプチャと比較によるテスト結果の検証は、時には必要ですが、非常に不安定で手間がかかる場合があります。

たとえば、特定のウィジェットは、プラットフォームやウィジェットのスタイルによって外観が異なる場合があるため、Qt がサポートするプラットフォームのセットが進化するにつれて、参照用ビットマップを何度も作成し、その後も維持管理する必要が生じる可能性があります。 したがって、ビットマップに影響を与える変更を行うということは、サポートされている各プラットフォームで期待されるビットマップを再作成しなければならないことを意味し、そのためには各プラットフォームへのアクセスが必要になります。

また、ビットマップの比較は、テストマシンの画面解像度、ビット深度、アクティブなテーマ、配色、ウィジェットスタイル、アクティブなロケール(通貨記号、テキストの方向など)、フォントサイズ、透明効果、ウィンドウマネージャの選択などの要因によって影響を受ける可能性があります。

可能な限り、ビットマップのキャプチャや比較を行うのではなく、オブジェクトや変数のプロパティの検証など、プログラム的な手段を使用してください。

テスト出力の改善

以下のセクションでは、読みやすく有益なテスト出力を生成するためのガイドラインを説明します。

警告のテスト

ソフトウェアをビルドする場合と同様に、テスト出力が警告で埋め尽くされていると、実際にバグの発生を示す手がかりとなる警告に気づきにくくなります。したがって、テストログを定期的にチェックして警告やその他の不要な出力を確認し、その原因を調査することが賢明です。 それらがバグの兆候である場合は、警告が発生した際にテストが失敗するように設定できます。

テスト対象のコードが、誤った使用法に関する警告などのメッセージを出力すべき場合は、そのように使用されたときに実際にメッセージが出力されるかどうかをテストすることも重要です。QTest::ignoreMessage() を使用することで、qWarning()、qDebug()、qInfo() などの関数によって生成される、被テストコードからの期待されるメッセージをテストできます。これにより、メッセージが生成されることが検証され、テスト実行の出力からそのメッセージが除外されます。メッセージが生成されない場合、テストは失敗します。

期待されるメッセージがQtがデバッグモードでビルドされた場合にのみ出力される場合は、QLibraryInfo::isDebugBuild() を使用して、Qtライブラリがデバッグモードでビルドされたかどうかを確認します。#ifdef QT_DEBUG を使用するだけでは不十分です。これはテスト自体がデバッグモードでビルドされたかどうかを示すだけであり、Qtライブラリも同様にデバッグモードでビルドされたことを保証するものではないからです。

テストでは、QTest::failOnWarning() を呼び出すことで、qWarning() の呼び出しが発生していないことを確認できます。パラメータを指定しない場合(Qt 6.8 以降)、警告が発生するとテストは失敗し、その警告が出力されます。 オプションで、failOnWarning() に、テスト対象の警告メッセージ、または照合対象のQRegularExpression を渡すことで、この動作を一致する警告に限定することができます。(これらのフィルタリング機能は Qt 6.3 で導入されました。)

また、環境変数 `QT_FATAL_WARNINGS ` を設定することで、警告を致命的なエラーとして扱うようにすることもできます。詳細についてはqWarning() を参照してください。これはオートテストに固有の機能ではありません。警告が膨大なテストログの中に埋もれてしまうような場合、この環境変数を設定して時折テストを実行することで、発生した警告を見つけ出し、排除するのに役立ちます。

autotest からのデバッグメッセージの出力を避ける

パスしたオートテストでは、未処理の警告やデバッグメッセージが出力されてはなりません。これにより、CIゲートは新しい警告やデバッグメッセージをテストの失敗として扱うことができます。コードのビルド時にコンパイラから出力される警告と同様に、警告がまれであれば問題の有用な手がかりとなりますが、日常的に発生する場合は、変更をテストしている開発者から重要な問題を隠してしまう可能性があります。

開発中にデバッグメッセージを追加することは問題ありませんが、テストをコミットする前に、これらを無効にするか削除する必要があります。

構造化された診断コードを書く

テストが失敗した際に役立つ診断出力は、コメントアウトされたり、プリプロセッサ指令によって無効化されたり、デバッグビルドでのみ有効化されたりするのではなく、通常のテスト出力の一部として含めるべきです。 継続的インテグレーション(CI)中にテストが失敗した場合、関連するすべての診断出力がCIログに記録されていれば、診断コードを有効にして再テストするよりも、大幅な時間の節約になります。特に、その失敗が自分のデスクトップ環境にないプラットフォームで発生した場合にはなおさらです。

テスト内の診断メッセージは、stdio.h やiostream.h といった出力メカニズムではなく、qDebug() やqWarning() といったQtの出力メカニズムを使用すべきです。後者の方法ではQtのメッセージ処理がバイパスされ、-silent というコマンドラインオプションで診断メッセージを抑制できなくなります。その結果、大量のデバッグ出力の中に重要な失敗メッセージが埋もれてしまう可能性があります。

テスト可能なコードの記述

以下のセクションでは、テストしやすいコードを書くためのガイドラインを説明します。

依存関係を切り離す

ユニットテストの考え方は、すべてのクラスを独立して使用することです。多くのクラスが他のクラスをインスタンス化しているため、1つのクラスを単独でインスタンス化することは不可能です。したがって、オブジェクトの作成と使用を分離する「依存性注入」と呼ばれる手法を使用する必要があります。ファクトリはオブジェクトツリーの構築を担当し、他のオブジェクトは抽象インターフェースを通じてこれらのオブジェクトを操作します。

この手法は、データ駆動型のアプリケーションではうまく機能します。一方、GUIアプリケーションの場合、オブジェクトが頻繁に生成・破棄されるため、このアプローチは困難になることがあります。抽象インターフェースに依存するクラスの正しい動作を検証するには、モックを使用することができます。例として、Googletest Mocking (gMock) フレームワークを参照してください。

すべてのクラスをライブラリにコンパイルする

中小規模のプロジェクトでは、通常、ビルドスクリプトですべてのソースファイルを列挙し、実行ファイルを一度にコンパイルします。これは、テスト用のビルドスクリプトでも、必要なソースファイルを再度列挙しなければならないことを意味します。

静的ライブラリを構築するスクリプト内で、ソースファイルとヘッダーファイルを一度だけ列挙する方が簡単です。そうすれば、main() 関数はその静的ライブラリに対してリンクされ、実行ファイルが構築されます。また、テストプログラムもその静的ライブラリに対してリンクされます。

複数のプログラムのビルドで同じソースファイルが使用されるプロジェクトでは、共有クラスを動的リンク(または共有オブジェクト)ライブラリにビルドし、テストプログラムを含む各プログラムが実行時にそれをロードできるようにする方が適切である場合があります。 繰り返しになりますが、コンパイル済みコードをライブラリにまとめることで、さまざまなプログラムを作成するためにどのコンポーネントを組み合わせるかを記述する際の重複を避けることができます。

テストマシンのセットアップ

以下のセクションでは、テストマシンのセットアップに起因する一般的な問題について説明します。

これらの問題はすべて、通常、仮想化を適切に活用することで解決できます。

スクリーンセーバー

スクリーンセーバーは、GUI クラスのテストの一部に干渉し、テスト結果の信頼性を損なう可能性があります。テスト結果の一貫性と信頼性を確保するため、スクリーンセーバーは無効にしてください。

システムダイアログ

オペレーティングシステムや他の実行中のアプリケーションによって予期せず表示されるダイアログは、自動テストに関与するウィジェットから入力フォーカスを奪い、再現不可能な失敗を引き起こす可能性があります。

典型的な問題の例としては、macOS のオンラインアップデート通知ダイアログ、ウイルススキャナによる誤検知、ウイルスシグネチャの更新などのスケジュールされたタスク、ワークステーションにプッシュされるソフトウェアアップデート、スタックの上部にウィンドウをポップアップさせるチャットプログラムなどが挙げられます。

ディスプレイの使用

一部のテストでは、テストマシンのディスプレイ、マウス、およびキーボードを使用するため、マシンが同時に他の用途で使用されている場合や、複数のテストが並行して実行されている場合に、テストが失敗する可能性があります。

CI システムでは、この問題を回避するために専用のテストマシンを使用していますが、専用のテストマシンがない場合は、セカンドディスプレイでテストを実行することでこの問題を解決できる可能性があります。

Unix では、Xephyr などのネストされた X サーバーや仮想 X サーバー上でテストを実行することも可能です。たとえば、Xephyr 上でテストの全セットを実行するには、以下のコマンドを実行します:

Xephyr :1 -ac -screen 1920x1200 >/dev/null 2>&1 &
sleep 5
DISPLAY=:1 icewm >/dev/null 2>&1 &
cd tests/auto
make
DISPLAY=:1 make -k -j1 check

NVIDIAのバイナリドライバをご利用の方は、XephyrではGLX拡張機能が利用できない場合がある点にご注意ください。MesaのlibGLを強制的に使用することで解決できる場合があります:

export LD_PRELOAD=/usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1

ただし、Xephyrと実際のXサーバーで異なるバージョンのlibGLを使用してテストを実行すると、QMLのディスクキャッシュが原因でテストがクラッシュする可能性があります。これを回避するには、QML_DISABLE_DISK_CACHE=1 を使用してください。

あるいは、オフスクリーンプラグインを使用してください:

TESTARGS="-platform offscreen" make check -k -j1

ウィンドウマネージャ

Unix では、少なくとも 2 つの自動テスト(tst_examples およびtst_gestures )が、ウィンドウマネージャの実行を必要とします。したがって、ネストされた X サーバー下でこれらのテストを実行する場合は、その X サーバー内でもウィンドウマネージャを実行する必要があります。

お使いのウィンドウマネージャは、すべてのウィンドウをディスプレイ上に自動的に配置するように設定されている必要があります。Tab Window Manager (twm) などの一部のウィンドウマネージャには、新しいウィンドウを手動で配置するモードがあり、これによりユーザー操作なしではテストスイートを実行できなくなります。

注:Tab Window Managerは、Qtのオートテストスイート全体を実行するには適していません。tst_gestures のオートテストを実行すると、設定が失われ、手動でのウィンドウ配置に戻ってしまうためです。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.