Skip to main content

このバージョンの GitHub Enterprise サーバーはこの日付をもって終了となります: 2026-04-09. 重大なセキュリティの問題に対してであっても、パッチリリースは作成されません。 パフォーマンスの向上、セキュリティの向上、新機能の向上を図るために、最新バージョンの GitHub Enterprise サーバーにアップグレードしてください。 アップグレードに関するヘルプについては、GitHub Enterprise サポートにお問い合わせください

カスタム クエリのテスト

新しい CodeQL のリリース後に、カスタム code scanning クエリを確認し、結果に影響を与える前に破壊的な変更を見つけてください。

この機能を使用できるユーザーについて

CodeQL は、次の種類のリポジトリで使用できます:

カスタム クエリのテスト

          CodeQL には、クエリの自動回帰テスト用の簡単なテスト フレームワークが用意されています。 クエリをテストして、期待どおりに動作することを確認します。

クエリ テスト中に、 CodeQL は、ユーザーがクエリが生成すると予想される結果を、実際に生成されたものと比較します。 期待される結果と実際の結果が異なる場合、クエリ テストは失敗します。 テストを修正するには、実際の結果と期待される結果が正確に一致するまで、クエリと期待される結果を反復処理する必要があります。 このトピックでは、テスト ファイルを作成し、test run サブコマンドを使用してそれに対してテストを実行する方法について説明します。

カスタム クエリ用のテスト CodeQL パックの設定

すべての CodeQL テストは、特別な "テスト" CodeQL パックに格納する必要があります。 つまり、次を定義する qlpack.yml ファイルを含むテスト ファイルのディレクトリです。

name: <name-of-test-pack>
version: 0.0.0
dependencies:
  <codeql-libraries-and-queries-to-test>: "*"
extractor: <language-of-code-to-test>
          `dependencies`値は、テストするクエリを含むCodeQL パックを指定します。

通常、これらのパックはソースから解決されるため、パックの固定バージョンを指定する必要はありません。 extractorでは、この CodeQL パックに格納されているコード ファイルからテスト データベースを作成するために CLI が使用する言語を定義します。 詳細については、「CodeQL パックを使った分析のカスタマイズ」を参照してください。

クエリ テストが CodeQL リポジトリでどのように編成されているかを確認すると便利な場合があります。 各言語には、コードベースを分析するためのライブラリとクエリを含む src ディレクトリ、ql/<language>/ql/src があります。 src ディレクトリと共に、これらのライブラリとクエリのテストを含む test ディレクトリがあります。

test ディレクトリは、次の 2 つのサブディレクトリを含むテスト CodeQL パックとして構成されます。

  •         `query-tests` は `src` ディレクトリに格納されているクエリのテストを含む一連のサブディレクトリです。 各サブディレクトリには、テスト コードと、テストするクエリを指定する QL 参照ファイルが含まれています。
    
  •         `library-tests` は、QL ライブラリ ファイルのテストを含む一連のサブディレクトリです。 各サブディレクトリには、ライブラリの単体テストとして記述されたテスト コードとクエリが含まれています。
    
            `qlpack.yml` ファイルができたら、すべての依存関係がダウンロードされ、CLI で使えるようにする必要があります。 これを行うには、`qlpack.yml` ファイルと同じディレクトリで次のコマンドを実行します。
    
codeql pack install

その結果、このパックでクエリを実行するために必要な一時的依存関係を全部指定する codeql-pack.lock.yml ファイルが作られます。 このファイルはソース管理にチェックインしてください。

クエリのテスト ファイルの設定

テストするクエリごとに、テスト CodeQL パックにサブディレクトリを作成する必要があります。 次に、test コマンドを実行する前に、次のファイルをサブディレクトリに追加します。

  • テストするクエリの場所を定義するクエリ参照ファイル (.qlref ファイル)。 場所は、クエリを含む CodeQL パックのルートを基準にして定義されます。 通常、これはテスト パックの CodeQL ブロックで指定されたdependencies パックです。 詳細については、「クエリ参照ファイル」を参照してください。

    テストするクエリがテスト ディレクトリに格納されている場合は、クエリ参照ファイルを追加する必要はありませんが、通常はテストとは別にクエリを格納することをお勧めします。 唯一の例外が QL ライブラリの単体テストで、これはアラートやパスを生成するクエリとは別に、テスト パックに格納される傾向があります。

  • クエリを実行するサンプル コード。 これは、クエリで識別するように設計されたサンプル コードを含む 1 つ以上のファイルで構成されている必要があります。

また、.expected という拡張子を持つファイルを作成することで、サンプル コードに対してクエリを実行するときに期待される結果を定義することもできます。 または、test コマンドをそのまま使用して .expected ファイルを作成することもできます。

クエリを作成してテストする方法の例については、次のをご覧ください。

メモ

          `.ql`、`.qlref`、および `.expected` のファイルの名前は一貫している必要があります。
  • test コマンドで .ql ファイル自体を直接指定する場合は、対応する .expected ファイルと同じベース名が必要です。 たとえば、クエリが MyJavaQuery.ql、期待される結果ファイルは MyJavaQuery.expected である必要があります。
  • コマンドで .qlref ファイルを指定する場合は、対応する .expected ファイルと同じベース名が必要ですが、クエリ自体の名前が異なるものにできます。
  • サンプル コード ファイルの名前は、他のテスト ファイルと一致している必要はありません。 .qlref (または .ql) ファイルとサブディレクトリの横にあるすべてのサンプル コード ファイルが、テスト データベースの作成に使用されます。 そのため、わかりやすくするために、互いの先祖であるディレクトリにはテスト ファイルを保存しないことをお勧めします。

実行中 codeql test run

          CodeQL クエリ テストは、次のコマンドを実行して実行されます。
codeql test run <test|dir>
          `<test|dir>` 引数は次のいずれかになります。

* .ql ファイルのパス。 * .qlref ファイルを参照する .ql ファイルのパス。 * .ql.qlref のファイルを再帰的に検索するディレクトリのパス。

次を指定することもできます。

  •         `--threads:` 必要に応じて、クエリの実行時に使用するスレッドの数。 既定のオプションは `1` です。 クエリの実行を高速化するために、より多くのスレッドを指定できます。 
            `0` を指定すると、スレッドの数が論理プロセッサの数と照合されます。
    

クエリのテスト時に使うことができるすべてのオプションについて詳しくは、「テストの実行」をご覧ください。

次の例は、Java コードで空の if ブロックを持つ then ステートメントを検索するクエリのテストを設定する方法を示します。 これには、カスタム クエリと対応するテスト ファイルを、CodeQL リポジトリのチェックアウト外のCodeQL パックに追加する手順が含まれています。 これにより、 CodeQL ライブラリを更新したり、別のブランチをチェックアウトしたりしても、カスタム クエリとテストは上書きされません。

クエリとテスト ファイルを準備する

  1. クエリを開発します。 たとえば、次の単純なクエリでは、Java コード内の空の then ブロックが検索されます。

    import java
    
    from IfStmt ifstmt
    where ifstmt.getThen() instanceof EmptyStmt
    select ifstmt, "This if statement has an empty then."
    
  2. 他のカスタム クエリを含むクエリを、ディレクトリ内の EmptyThen.ql という名前のファイルに保存します。 たとえば、「 custom-queries/java/queries/EmptyThen.ql 」のように入力します。

  3.        CodeQL パックにカスタム クエリをまだ追加していない場合は、ここでCodeQLパックを作成します。 たとえば、カスタム Java クエリが `custom-queries/java/queries` に格納されている場合は、次の内容の `qlpack.yml` ファイルを `custom-queries/java/queries` に追加します。
    
    name: my-custom-queries
    dependencies:
      codeql/java-queries: "*"
    
           CodeQL パックの詳細については、「[AUTOTITLE](/code-security/codeql-cli/getting-started-with-the-codeql-cli/customizing-analysis-with-codeql-packs)」を参照してください。
    
  4. 次の内容を含むCodeQL ファイルをqlpack.ymlに追加し、カスタム クエリの custom-queries/java/tests パックの名前と一致するようにdependenciesを更新して、Java テスト用のCodeQL パックを作成します。

    次の qlpack.yml ファイルは、my-github-user/my-query-tests が 1.2.3 以上で 2.0.0 未満のバージョンの my-github-user/my-custom-queries に依存していることを示しています。 また、テスト データベースの作成時に CLI で Java extractor を使用する必要があることを宣言します。 tests: . 行では、--strict-test-discovery オプションを指定して codeql test run を実行する際に、パック内のすべての .ql ファイルをテストとして実行する必要があることを宣言します。 通常、テスト パックに version プロパティは含まれません。 これにより、それらが誤って発行されるのを防ぐことができます。

    name: my-github-user/my-query-tests
    dependencies:
      my-github-user/my-custom-queries: ^1.2.3
    extractor: java-kotlin
    tests: .
    
  5. テスト ディレクトリのルートで codeql pack install を実行します。 その結果、このパックでクエリを実行するために必要な一時的依存関係を全部指定する codeql-pack.lock.yml ファイルが作られます。

  6. Java テスト パック内で、EmptyThen.ql に関連付けられているテスト ファイルを格納するディレクトリを作成します。 たとえば、「 custom-queries/java/tests/EmptyThen 」のように入力します。

  7. 新しいディレクトリで、EmptyThen.qlref を作成 して EmptyThen.ql の場所を定義します。 クエリへのパスは、クエリを含む CodeQL パックのルートを基準にして指定する必要があります。 この場合、クエリは CodeQL という名前の my-custom-queries パックの最上位ディレクトリにあり、my-query-testsの依存関係として宣言されています。 したがって、EmptyThen.qlref には EmptyThen.ql のみを含める必要があります。

  8. テストするコード スニペットを作成します。 次の Java コードには、3 行目に空の if ステートメントが含まれています。 それを custom-queries/java/tests/EmptyThen/Test.java に保存します。

    class Test {
      public void problem(String arg) {
        if (arg.isEmpty())
          ;
        {
          System.out.println("Empty argument");
        }
      }
    
      public void good(String arg) {
        if (arg.isEmpty()) {
          System.out.println("Empty argument");
        }
      }
    }
    

テストを実行する

テストを実行するには、custom-queries ディレクトリに移動して codeql test run java/tests/EmptyThen を実行します。

テストを実行すると、次のようになります。

  1.        `EmptyThen` ディレクトリ内の 1 つのテストが検索されます。
    
  2.        CodeQL ディレクトリに格納されている`.java` ファイルから`EmptyThen` データベースを抽出します。
    
  3.        `EmptyThen.qlref` ファイルによって参照されるクエリがコンパイルされます。
    

    この手順が失敗した場合は、CLI でカスタム CodeQL パックが見つからないためです。 コマンドを再実行し、カスタム CodeQL パックの場所を指定します。次に例を示します。

    codeql test run --search-path=java java/tests/EmptyThen

    構成の一環として検索パスを保存することに関する詳細については、「CodeQL の構成ファイルでコマンド オプションを指定する」を参照してください。

  4. クエリが実行され、EmptyThen.actual 結果ファイルが生成されて、テストが実行されます。

  5.        `EmptyThen.expected` ファイルを確認して、`.actual` 結果ファイルと比較されます。
    
  6. テストの結果 (この場合はエラー 0 tests passed; 1 tests failed:) が報告されます。 クエリの期待される結果を含むファイルをまだ追加していないため、テストは失敗しました。

クエリ テストの出力を表示する

          CodeQL は、 `EmptyThen` ディレクトリに次のファイルを生成します。

* EmptyThen.actual。クエリによって生成された実際の結果を含むファイルです。 * EmptyThen.testprojは、 VS Code に読み込み、失敗したテストのデバッグに使用できるテスト データベースです。 テストが正常に完了すると、このデータベースはハウスキープ処理で削除されます。 test run オプションを使用して --keep-databases を実行することで、この手順をオーバーライドできます。

この場合、エラーが予想されますが、修正は簡単です。 EmptyThen.actual ファイルを開くと、テストの結果が表示されます。


| Test.java:3:5:3:22 | stmt | This if statement has an empty then. |

このファイルには、クエリが出力する select 句の各部分の個別の列と共に、結果の場所の列を含むテーブルが含まれています。 結果は期待どおりであるため、ファイル拡張子を更新して、このテストで期待される結果 (EmptyThen.expected) として定義できます。

ここでテストを再実行すると、出力は似たものになりますが、完了時に All 1 tests passed. が報告されます。

クエリの結果が変更された場合 (たとえば、クエリの select ステートメントを変更した場合)、テストは失敗します。 失敗した結果の場合、CLI 出力には EmptyThen.expectedEmptyThen.actual のファイルの統合された差分が含まれます。 この情報で、簡単なテスト エラーを十分デバッグできる場合があります。

デバッグが困難なエラーの場合は、EmptyThen.testprojのCodeQLにVS Codeをインポートし、EmptyThen.qlを実行して、Test.javaサンプル コードで結果を表示できます。 詳細については、「CodeQL データベースの管理」を参照してください。

詳細については、次を参照してください。