This product is not supported for your selected Datadog site. ().

互換性

サポート対象言語:

言語バージョン
Python 2>= 2.7
Python 3>= 3.6

サポート対象テストフレームワーク:

テストフレームワークバージョン
pytest>= 3.0.0
pytest-benchmark>= 3.1.0
unittest>= 3.7
Bazel を使用して Python テストを実行する場合は、Datadog の Python テスト用 Bazel ルールを使用します。

報告方法の構成

Datadog にテスト結果を報告するには、Datadog Python ライブラリを構成する必要があります。

We support auto-instrumentation for the following CI providers:

CI ProviderAuto-Instrumentation method
GitHub ActionsDatadog Test Visibility Github Action
JenkinsUI-based configuration with Datadog Jenkins plugin
GitLabDatadog Test Visibility GitLab Script
CircleCIDatadog Test Visibility CircleCI Orb

Auto-instrumentation runs on the CI executor and does not automatically apply to tests in a separate container. Before using it for containerized tests, see Tests in Containers.

If the auto-instrumentation step configures the process that runs your tests, you can skip the rest of the setup steps below.

If you are using a cloud CI provider without access to the underlying worker nodes, such as GitHub Actions or CircleCI, configure the library to use the Agentless mode. For this, set the following environment variables:

Set these variables before starting the test process. For parallel test runners, set them on the parent process so every worker inherits them.

DD_CIVISIBILITY_AGENTLESS_ENABLED=true selects Agentless mode. DD_API_KEY provides authentication but does not enable Agentless mode.

DD_CIVISIBILITY_AGENTLESS_ENABLED=true (Required for Agentless mode)
Enables Agentless mode to send test results directly to Datadog.
Default: false
DD_API_KEY (Required for Agentless mode)
The Datadog API key used to authenticate test result uploads.
Default: (empty)

If you use a Datadog site other than US1, set the following variable:

DD_SITE (Optional for Agentless mode)
The Datadog site to upload results to.
Default: datadoghq.com

If you are running tests on an on-premises CI provider, such as Jenkins or self-managed GitLab CI, install the Datadog Agent on each worker node by following the Agent installation instructions. This is the recommended option as it allows you to automatically link test results to logs and underlying host metrics.

If you are using a Kubernetes executor, Datadog recommends using the Datadog Operator. The operator includes Datadog Admission Controller which can automatically inject the tracer library into the build pods. Note: If you use the Datadog Operator, there is no need to download and inject the tracer library since the Admission Controller can do this for you, so you can skip the corresponding step below. However, you still need to make sure that your pods set the environment variables or command-line parameters necessary to enable Test Visibility.

If you are not using Kubernetes or can’t use the Datadog Admission Controller and the CI provider is using a container-based executor, set the DD_TRACE_AGENT_URL environment variable (which defaults to http://localhost:8126) in the build container running the tracer to an endpoint that is accessible from within that container. Note: Using localhost inside the build references the container itself and not the underlying worker node or any container where the Agent might be running in.

DD_TRACE_AGENT_URL includes the protocol and port (for example, http://localhost:8126) and takes precedence over DD_AGENT_HOST and DD_TRACE_AGENT_PORT, and is the recommended configuration parameter to configure the Datadog Agent’s URL for CI Visibility.

If you still have issues connecting to the Datadog Agent, use the Agentless Mode. Note: When using this method, tests are not correlated with logs and infrastructure metrics.

Python トレーサーのインストール

次のコマンドを実行して、Python トレーサーをインストールします。

pip install -U ddtrace

詳細については、Python トレーサーのインストールドキュメントを参照してください。

テストのインスツルメンテーション

pytest テストのインスツルメンテーションを有効にするには、pytest の実行時に --ddtrace オプションを追加します。

pytest --ddtrace

もし、残りの APM インテグレーションも有効にして flamegraph でより多くの情報を取得したい場合は、--ddtrace-patch-all オプションを追加します。

pytest --ddtrace --ddtrace-patch-all

追加の構成については、構成設定を参照してください。

テストにカスタムタグを追加する

テストにカスタムタグを追加するには、テストの引数として ddspan を宣言します。

from ddtrace import tracer

# Declare `ddspan` as argument to your test
def test_simple_case(ddspan):
    # Set your tags
    ddspan.set_tag("test_owner", "my_team")
    # test continues normally
    # ...

これらのタグに対してフィルターや group by フィールドを作成するには、まずファセットを作成する必要があります。タグの追加について詳しくは、Python カスタムインスツルメンテーションのドキュメントのタグの追加セクションを参照してください。

テストへのカスタム測定値の追加

タグと同様に、テストにカスタム測定値を追加するには、現在アクティブなスパンを使用します。

from ddtrace import tracer

# Declare `ddspan` as an argument to your test
def test_simple_case(ddspan):
    # Set your tags
    ddspan.set_tag("memory_allocations", 16)
    # test continues normally
    # ...

カスタム測定値の詳細については、カスタム測定値の追加ガイドを参照してください。

pytest-benchmarkでベンチマークテストをインスツルメンテーションするには、pytestの実行時に--ddtraceオプションを指定してベンチマークテストを実行します。Datadog は pytest-benchmark からメトリクスを自動的に検出します。

def square_value(value):
    return value * value


def test_square_value(benchmark):
    result = benchmark(square_value, 5)
    assert result == 25

追加の構成については、構成設定を参照してください。

unittest テストのインスツルメンテーションを有効にするには、unittest コマンドの先頭に ddtrace-run を追加してテストを実行します。

ddtrace-run python -m unittest

unittest インスツルメンテーションを手動で有効にする場合は、patch() を使用してインテグレーションを有効にします。

from ddtrace import patch
import unittest
patch(unittest=True)

class MyTest(unittest.TestCase):
def test_will_pass(self):
assert True

追加の構成については、構成設定を参照してください。

手動テスト API

Test Optimization 手動テスト API はベータ版であり、変更される可能性があります。

バージョン 2.13.0 以降、Datadog Python SDK は、必要に応じて Test Optimization の結果を送信するための Test Optimization API (ddtrace.ext.test_visibility) を提供しています。

API の実行

この API はクラスを使用して、Test Optimization イベントを送信するための名前空間付きメソッドを提供します。

テスト実行には 2 つのフェーズがあります。

  • 検出: 期待される項目を API に通知します
  • 実行: 結果を送信します (開始および終了の呼び出しを使用)

検出フェーズと実行フェーズが分かれているため、テストランナープロセスがテストを収集してからテストが開始されるまでの間にギャップを設けることができます。

API ユーザーは、API の状態ストレージ内で Test Optimization 項目の参照として使用される一貫した識別子 (後述) を提供する必要があります。

有効化 test_visibility

Test Optimization API を使用する前に、ddtrace.ext.test_visibility.api.enable_test_visibility() 関数を呼び出す必要があります。

データの適切なフラッシュを確実に行うため、プロセス終了前に ddtrace.ext.test_visibility.api.disable_test_visibility() 関数を呼び出してください。

ドメインモデル

この API は、テストセッション、テストモジュール、テストスイート、テストの 4 つの概念に基づいています。

モジュール、スイート、およびテストは Python Test Optimization API 内で階層を形成しており、項目識別子の親子関係によって表されます。

テストセッション

テストセッションはプロジェクトのテスト実行を表し、通常はテストコマンドの実行に対応します。Test Optimization プログラムの実行において、検出、開始、終了できるセッションは 1 つだけです。

ddtrace.ext.test_visibility.api.TestSession.discover() を呼び出してセッションを検出し、テストコマンド、指定されたフレームワーク名、およびバージョンを渡します。

ddtrace.ext.test_visibility.api.TestSession.start() を呼び出してセッションを開始します。

テストが完了したら、ddtrace.ext.test_visibility.api.TestSession.finish() を呼び出してください。

テストモジュール

テストモジュールは、プロジェクトのテスト実行におけるより小さな作業単位 (ディレクトリなど) を表します。

モジュール名をパラメーターとして指定して ddtrace.ext.test_visibility.api.TestModuleId() を呼び出し、TestModuleId を作成します。

TestModuleId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.TestModule.discover() を呼び出し、モジュールを検出します。

TestModuleId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.TestModule.start() を呼び出し、モジュールを開始します。

モジュール内のすべての子項目が完了したら、TestModuleId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.TestModule.finish() を呼び出してください。

テストスイート

テストスイートは、プロジェクトのモジュール内のテストのサブセット (例: .py ファイル) を表します。

親モジュールの TestModuleId とスイート名を引数として指定して ddtrace.ext.test_visibility.api.TestSuiteId() を呼び出し、TestSuiteId を作成します。

TestSuiteId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.TestSuite.discover() を呼び出し、スイートを検出します。

TestSuiteId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.TestSuite.start() を呼び出し、スイートを開始します。

スイート内のすべての子項目が完了したら、TestSuiteId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.TestSuite.finish() を呼び出してください。

テスト

テストは、テストスイートの一部として実行される単一のテストケースを表します。

親スイートの TestSuiteId とテスト名を引数として指定して ddtrace.ext.test_visibility.api.TestId() を呼び出し、TestId を作成します。TestId() メソッドは、オプションの parameters 引数として JSON 解析可能な文字列を受け取ります。parameters 引数は、名前は同じでもパラメーター値が異なるパラメーター化されたテストを区別するために使用できます。

TestId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.Test.discover() を呼び出し、テストを検出します。Test.discover() クラスメソッドは、オプションの resource パラメーターとして文字列を受け取ります。このパラメーターのデフォルト値は TestId の name です。

TestId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.Test.start() を呼び出し、テストを開始します。

TestId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.Test.mark_pass() を呼び出し、テストが正常に完了したことをマークします。 TestId オブジェクトを引数として渡して ddtrace.ext.test_visibility.api.Test.mark_fail() を呼び出し、テストが失敗したことをマークします。mark_fail() は、オプションの TestExcInfo オブジェクトを exc_info パラメーターとして受け取ります。 ddtrace.ext.test_visibility.api.Test.mark_skip() を呼び出し、TestId オブジェクトを引数として渡すことで、テストがスキップされたことをマークします。mark_skip() は、オプションの文字列を skip_reason パラメーターとして受け取ります。

例外情報

ddtrace.ext.test_visibility.api.Test.mark_fail()クラスメソッドは、テストの失敗中に発生した例外に関する情報を保持します。

ddtrace.ext.test_visibility.api.TestExcInfo()メソッドは、3 つの位置パラメーターを受け取ります。

  • exc_type: 発生した例外の型
  • exc_value: 例外のBaseExceptionオブジェクト
  • exc_traceback: 例外のTracebackオブジェクト
コードオーナー情報

ddtrace.ext.test_visibility.api.Test.discover()クラスメソッドは、オプションのリスト (文字列のリスト) をcodeownersパラメーターとして受け取ります。

テストソースファイル情報

ddtrace.ext.test_visibility.api.Test.discover()クラスメソッドは、オプションのTestSourceFileInfoオブジェクトをsource_file_infoパラメーターとして受け取ります。TestSourceFileInfoオブジェクトは、特定のテストのパス、およびオプションで開始行と終了行を表します。

ddtrace.ext.test_visibility.api.TestSourceFileInfo()メソッドは、3 つの位置パラメーターを受け取ります。

  • path: pathlib.Pathオブジェクト (Test Optimization API によってリポジトリルートからの相対パスに変換されます)
  • start_line: ファイル内のテストの開始行を表すオプションの整数
  • end_line: ファイル内のテストの終了行を表すオプションの整数
テスト検出後のパラメーター設定

ddtrace.ext.test_visibility.api.Test.set_parameters()クラスメソッドは、TestIdオブジェクトを引数として、JSON 解析可能な文字列を受け取り、テストのparametersを設定します。

注: これはテストに関連付けられたパラメーターを上書きしますが、TestId オブジェクトの parameters フィールドは変更しません。

テストが検出された後にパラメーターを設定するには、parameters フィールドが設定されていない場合でも TestId オブジェクトが一意である必要があります。

コード例

from ddtrace.ext.test_visibility import api
import pathlib
import sys

if __name__ == "__main__":
    # Enable the Test Optimization service
    api.enable_test_visibility()

    # Discover items
    api.TestSession.discover("manual_test_api_example", "my_manual_framework", "1.0.0")
    test_module_1_id = api.TestModuleId("module_1")
    api.TestModule.discover(test_module_1_id)

    test_suite_1_id = api.TestSuiteId(test_module_1_id, "suite_1")
    api.TestSuite.discover(test_suite_1_id)

    test_1_id = api.TestId(test_suite_1_id, "test_1")
    api.Test.discover(test_1_id)

    # A parameterized test with codeowners and a source file
    test_2_codeowners = ["team_1", "team_2"]
    test_2_source_info = api.TestSourceFileInfo(pathlib.Path("/path/to_my/tests.py"), 16, 35)

    parametrized_test_2_a_id = api.TestId(
        test_suite_1_id,
        "test_2",
        parameters='{"parameter_1": "value_is_a"}'
    )
    api.Test.discover(
        parametrized_test_2_a_id,
        codeowners=test_2_codeowners,
        source_file_info=test_2_source_info,
        resource="overriden resource name A",
    )

    parametrized_test_2_b_id = api.TestId(
        test_suite_1_id,
        "test_2",
        parameters='{"parameter_1": "value_is_b"}'
    )
    api.Test.discover(
      parametrized_test_2_b_id,
      codeowners=test_2_codeowners,
      source_file_info=test_2_source_info,
      resource="overriden resource name B"
    )

    test_3_id = api.TestId(test_suite_1_id, "test_3")
    api.Test.discover(test_3_id)

    test_4_id = api.TestId(test_suite_1_id, "test_4")
    api.Test.discover(test_4_id)


    # Start and execute items
    api.TestSession.start()

    api.TestModule.start(test_module_1_id)
    api.TestSuite.start(test_suite_1_id)

    # test_1 passes successfully
    api.Test.start(test_1_id)
    api.Test.mark_pass(test_1_id)

    # test_2's first parametrized test succeeds, but the second fails without attaching exception info
    api.Test.start(parametrized_test_2_a_id)
    api.Test.mark_pass(parametrized_test_2_a_id)

    api.Test.start(parametrized_test_2_b_id)
    api.Test.mark_fail(parametrized_test_2_b_id)

    # test_3 is skipped
    api.Test.start(test_3_id)
    api.Test.mark_skip(test_3_id, skip_reason="example skipped test")

    # test_4 fails, and attaches exception info
    api.Test.start(test_4_id)
    try:
      raise(ValueError("this test failed"))
    except:
      api.Test.mark_fail(test_4_id, exc_info=api.TestExcInfo(*sys.exc_info()))

    # Finish suites and modules
    api.TestSuite.finish(test_suite_1_id)
    api.TestModule.finish(test_module_1_id)
    api.TestSession.finish()

追加の構成については、構成設定を参照してください。

構成設定

SDK を構成するには、テストプロセスを開始する前に以下の環境変数を設定します。並列テストランナーの場合、すべてのワーカーが継承するように親プロセスで設定してください。

DD_SERVICE(オプション)
テスト対象のサービスまたはライブラリの名前。
デフォルト: リポジトリ名。利用できない場合は、pytest 用の test または unittest 用の unittest を使用してください。
例: my-python-app
DD_ENV (オプション)
テストが実行されている環境の名前。
デフォルト: none
例: local、ci
DD_CIVISIBILITY_AGENTLESS_ENABLED=true (Agentless モードの場合、必須)
Agentless モードを有効にして、テスト結果を Datadog に直接送信します。
デフォルト: false
DD_API_KEY (Agentless モードの場合、必須)
テスト結果のアップロードを認証するために使用される Datadog API キー。この変数で Agentless モードが有効になることはありません。
デフォルト: (empty)
DD_SITE (Agentless モードの場合、オプション)
テスト結果のアップロード先の Datadog サイト。US1 以外のサイトを使用する場合は、この構成を設定します。
デフォルト: datadoghq.com
DD_TRACE_AGENT_URL (Datadog Agent を使用する場合のみ)
トレース収集用の Datadog Agent URL。http://hostname:port の形式にします。
デフォルト: http://localhost:8126
DD_TEST_SESSION_NAME (オプション)
unit-tests、integration-tests、smoke-tests などのテストグループを識別します。
デフォルト: CI ジョブ名とテストコマンド、または CI ジョブ名が利用できない場合はテストコマンド。
例: unit-tests、integration-tests、smoke-tests

service および env の予約タグの詳細については、Unified Service Tagging を参照してください。

他のすべての Datadog トレーサーコンフィギュレーションオプションも使用できます。

Git のメタデータを収集する

Datadog uses Git information for visualizing your test results and grouping them by repository, branch, and commit. Git metadata is automatically collected by the test instrumentation from CI provider environment variables and the local .git folder in the project path, if available.

If you are running tests in non-supported CI providers or with no .git folder, you can set the Git information manually using environment variables. These environment variables take precedence over any auto-detected information. Set the following environment variables to provide Git information:

DD_GIT_REPOSITORY_URL
URL of the repository where the code is stored. Both HTTP and SSH URLs are supported.
Example: git@github.com:MyCompany/MyApp.git, https://github.com/MyCompany/MyApp.git
DD_GIT_BRANCH
Git branch being tested. Leave empty if providing tag information instead.
Example: develop
DD_GIT_TAG
Git tag being tested (if applicable). Leave empty if providing branch information instead.
Example: 1.0.1
DD_GIT_COMMIT_SHA
Full commit hash.
Example: a18ebf361cc831f5535e58ec4fae04ffd98d8152
DD_GIT_COMMIT_MESSAGE
Commit message.
Example: Set release number
DD_GIT_COMMIT_AUTHOR_NAME
Commit author name.
Example: John Smith
DD_GIT_COMMIT_AUTHOR_EMAIL
Commit author email.
Example: john@example.com
DD_GIT_COMMIT_AUTHOR_DATE
Commit author date in ISO 8601 format.
Example: 2021-03-12T16:00:28Z
DD_GIT_COMMIT_COMMITTER_NAME
Commit committer name.
Example: Jane Smith
DD_GIT_COMMIT_COMMITTER_EMAIL
Commit committer email.
Example: jane@example.com
DD_GIT_COMMIT_COMMITTER_DATE
Commit committer date in ISO 8601 format.
Example: 2021-03-12T16:00:28Z

ベストプラクティス

テストセッション名 DD_TEST_SESSION_NAME

DD_TEST_SESSION_NAME を使用してテストセッションの名前と関連するテストグループを定義します。このタグの値の例は次のとおりです。

  • unit-tests
  • integration-tests
  • smoke-tests
  • flaky-tests
  • ui-tests
  • backend-tests

DD_TEST_SESSION_NAME が指定されていない場合、デフォルトで CI ジョブ名とテストコマンドになります。CI ジョブ名が利用できない場合は、テストコマンドが使用されます。

異なるテストグループを区別しやすくするため、テストセッション名はリポジトリ内で一意でなければなりません。

DD_TEST_SESSION_NAME を使用するタイミング

Datadog がテストセッション間の対応関係を確立するためにチェックするパラメーターのセットがあります。テストの実行に使用されるテストコマンドもその 1 つです。一時フォルダーなど、実行ごとに変化する文字列がテストコマンドに含まれる場合、Datadog はそれらのセッションを互いに無関係なものとみなします。たとえば、以下のような場合です。

  • pytest --temp-dir=/var/folders/t1/rs2htfh55mz9px2j4prmpg_c0000gq/T

テストコマンドが実行ごとに異なる場合、Datadog は DD_TEST_SESSION_NAME を使用することを推奨します。

既知の制限

テスト実行を変更する pytest 用のプラグインは、予期しない動作を引き起こす可能性があります。

並列化

pytest に並列化を導入するプラグイン (pytest-xdist や pytest-forked など) は、並列化されたインスタンスごとに 1 つのセッションイベントを作成します。

これらのプラグインを ddtrace と併用するといくつかの問題が発生しますが、最近の dd-trace-py のバージョン (3.12.6 以降) では pytest-xdist について解決されています。たとえば、個々のテストが失敗しても、セッション、モジュール、またはスイートが合格する場合があります。同様に、すべてのテストが合格しても、スイート/セッション/モジュールが失敗する可能性があります。これは、これらのプラグインがワーカーサブプロセスを作成し、親プロセスで作成されたスパンが子プロセスからの結果を反映しない可能性があるために発生します。このため、現時点では ddtrace と pytest-forked の併用はサポートされておらず、pytest-xdist は ddtrace>=3.12.6 のみをサポートしています。

各ワーカーはテスト結果を Datadog に個別に報告するため、異なるプロセスで実行されている同じモジュールのテストは、別々のモジュールイベントまたはスイートイベントを生成します。

テストイベントの全体数 (およびその正確性) は影響を受けません。個別のセッション、モジュール、またはスイートのイベントは、同じ pytest 実行 (pytest-forked を含む) 内の他のイベントと結果が一致しない場合があります。

テストの順序付け

テスト実行の順序を変更するプラグイン (pytest-randomly など) は、複数のモジュールイベントやスイートイベントを作成する可能性があります。モジュールイベントやスイートイベントの期間と結果も、pytest によって報告される結果と一致しない場合があります。

テストイベントの総数 (およびその正確性) は影響を受けません。

場合によっては、unittest テスト実行を並列で実行すると、インスツルメンテーションが破損し、テストの最適化に影響を与える可能性があります。

Datadog では、テストの最適化への影響を防ぐため、一度に最大 1 つのプロセスを使用することを推奨しています。

参考資料