Este producto no es compatible con el sitio Datadog seleccionado. ().

Compatibilidad

Idiomas admitidos:

IdiomaVersión
Python 2>= 2.7
Python 3>= 3.6

Marcos de prueba compatibles:

Framework de pruebaVersión
pytest>= 3.0.0
pytest-benchmark>= 3.1.0
unittest>= 3.7
Si utiliza Bazel para ejecutar pruebas de Python, utilice las reglas de Datadog para Bazel en pruebas de Python.

Configuración del método de reporte

Para reportar los resultados de las pruebas a Datadog, necesita configurar la biblioteca de Python de Datadog:

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.

Instalación del rastreador de Python

Instale el rastreador de Python ejecutando:

pip install -U ddtrace

Para obtener más información, consulte la documentación de instalación del rastreador de Python.

Instrumentación de sus pruebas

Para habilitar la instrumentación de pruebas de pytest, agregue la opción --ddtrace al ejecutar pytest.

pytest --ddtrace

Si también desea habilitar el resto de las integraciones de APM para obtener más información en su flamegraph, agregue la opción --ddtrace-patch-all:

pytest --ddtrace --ddtrace-patch-all

Para obtener información de configuración adicional, consulte Configuración.

Agregar etiquetas personalizadas a las pruebas

Para agregar etiquetas personalizadas a sus pruebas, declare ddspan como un argumento en su prueba:

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
    # ...

Para crear filtros o group by campos para estas etiquetas, primero debe crear facetas. Para obtener más información sobre cómo agregar etiquetas, consulte la sección Adding Tags de la documentación de instrumentación personalizada de Python.

Agregar medidas personalizadas a las pruebas

Al igual que con las etiquetas, para agregar medidas personalizadas a sus pruebas, utilice el span activo actual:

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
    # ...

Lea más sobre las métricas personalizadas en la Guía para agregar métricas personalizadas.

Para instrumentar sus pruebas de benchmark con pytest-benchmark, ejecute sus pruebas de benchmark con la opción --ddtrace al ejecutar pytest, y Datadog detecta las métricas de pytest-benchmark automáticamente:

def square_value(value):
    return value * value


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

Para configuraciones adicionales, consulte Configuración.

Para habilitar la instrumentación de pruebas de unittest, ejecute sus pruebas añadiendo ddtrace-run al principio de su comando unittest.

ddtrace-run python -m unittest

Alternativamente, si desea habilitar la instrumentación unittest manualmente, use patch() para habilitar la integración:

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

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

Para configuraciones adicionales, consulte Configuración.

API de pruebas manuales

La API de pruebas manuales de Test Optimization está en beta y está sujeta a cambios.

A partir de la versión 2.13.0, el Datadog Python SDK proporciona la API de Test Optimization (ddtrace.ext.test_visibility) para enviar resultados de optimización de pruebas según sea necesario.

Ejecución de la API

La API utiliza clases para proporcionar métodos con espacios de nombres para enviar eventos de Test Optimization.

La ejecución de pruebas tiene dos fases:

  • Descubrimiento: informar a la API qué elementos esperar
  • Ejecución: enviar resultados (usando llamadas de inicio y finalización)

Las fases distintas de descubrimiento y ejecución permiten un intervalo entre el proceso del ejecutor de pruebas que recopila las pruebas y el inicio de las mismas.

Los usuarios de la API deben proporcionar identificadores consistentes (descritos a continuación) que se utilizan como referencias para los elementos de Test Optimization dentro del almacenamiento de estado de la API.

Habilitar test_visibility

Debe llamar a la función ddtrace.ext.test_visibility.api.enable_test_visibility() antes de usar la API de Test Optimization.

Llame a la función ddtrace.ext.test_visibility.api.disable_test_visibility() antes del cierre del proceso para asegurar el vaciado adecuado de los datos.

Modelo de dominio

La API se basa en cuatro conceptos: sesión de prueba, módulo de prueba, conjunto de pruebas y prueba.

Los módulos, conjuntos de pruebas y pruebas forman una jerarquía en la API de Test Optimization de Python, representada por la relación de padre del identificador del elemento.

Sesión de prueba

Una sesión de prueba representa la ejecución de pruebas de un proyecto, que normalmente corresponde a la ejecución de un comando de prueba. Solo se puede descubrir, iniciar y finalizar una sesión en la ejecución del programa Test Optimization.

Llame a ddtrace.ext.test_visibility.api.TestSession.discover() para descubrir la sesión, pasando el comando de prueba, un nombre de framework determinado y la versión.

Llame a ddtrace.ext.test_visibility.api.TestSession.start() para iniciar la sesión.

Cuando las pruebas hayan finalizado, llame a ddtrace.ext.test_visibility.api.TestSession.finish() .

Módulo de prueba

Un módulo de prueba representa una unidad de trabajo más pequeña dentro de las pruebas de un proyecto (un directorio, por ejemplo).

Llame a ddtrace.ext.test_visibility.api.TestModuleId(), proporcionando el nombre del módulo como parámetro, para crear un TestModuleId.

Llame a ddtrace.ext.test_visibility.api.TestModule.discover(), pasando el objeto TestModuleId como argumento, para descubrir el módulo.

Llame a ddtrace.ext.test_visibility.api.TestModule.start(), pasando el objeto TestModuleId como argumento, para iniciar el módulo.

Después de que todos los elementos secundarios dentro del módulo hayan finalizado, llame a ddtrace.ext.test_visibility.api.TestModule.finish(), pasando el objeto TestModuleId como argumento.

Conjunto de Pruebas

Un conjunto de pruebas representa un subconjunto de pruebas dentro de los módulos de un proyecto (un archivo .py, por ejemplo).

Llame a ddtrace.ext.test_visibility.api.TestSuiteId(), proporcionando el TestModuleId del módulo principal y el nombre del conjunto de pruebas como argumentos, para crear un TestSuiteId.

Llame a ddtrace.ext.test_visibility.api.TestSuite.discover(), pasando el objeto TestSuiteId como argumento, para descubrir el conjunto de pruebas.

Llame a ddtrace.ext.test_visibility.api.TestSuite.start(), pasando el objeto TestSuiteId como argumento, para iniciar el conjunto de pruebas.

Después de que todos los elementos secundarios dentro del conjunto de pruebas hayan finalizado, llame a ddtrace.ext.test_visibility.api.TestSuite.finish(), pasando el objeto TestSuiteId como argumento.

Prueba

Una prueba representa una sola incidencia de prueba que se ejecuta como parte de un conjunto de pruebas.

Llame a ddtrace.ext.test_visibility.api.TestId(), proporcionando la TestSuiteId de la suite principal y el nombre de la prueba como argumentos, para crear una TestId. El método TestId() acepta una cadena analizable en formato JSON como el argumento opcional parameters. El argumento parameters se puede utilizar para distinguir pruebas parametrizadas que tienen el mismo nombre, pero diferentes valores de parámetros.

Llame a ddtrace.ext.test_visibility.api.Test.discover(), pasando el objeto TestId como argumento, para descubrir la prueba. El método de clase Test.discover() acepta una cadena como el parámetro opcional resource, que tiene como valor predeterminado el name del TestId.

Llame a ddtrace.ext.test_visibility.api.Test.start(), pasando el objeto TestId como argumento, para iniciar la prueba.

Llame a ddtrace.ext.test_visibility.api.Test.mark_pass(), pasando el objeto TestId como argumento, para marcar que la prueba ha pasado exitosamente. Llame a ddtrace.ext.test_visibility.api.Test.mark_fail(), pasando el objeto TestId como argumento, para marcar que la prueba ha fallado. mark_fail() acepta un objeto TestExcInfo opcional como el parámetro exc_info. Llame a ddtrace.ext.test_visibility.api.Test.mark_skip(), pasando el objeto TestId como argumento, para marcar que la prueba fue omitida. mark_skip() acepta una cadena opcional como el parámetro skip_reason.

Información de la excepción

El método de clase ddtrace.ext.test_visibility.api.Test.mark_fail() contiene información sobre las excepciones encontradas durante el fallo de una prueba.

El método ddtrace.ext.test_visibility.api.TestExcInfo() toma tres parámetros posicionales:

  • exc_type: el tipo de excepción encontrada
  • exc_value: el objeto BaseException para la excepción
  • exc_traceback: el objeto Traceback para la excepción
Información del propietario del código

El método de clase ddtrace.ext.test_visibility.api.Test.discover() acepta una lista de cadenas opcional como el parámetro codeowners.

Información del archivo fuente de la prueba

El método de clase ddtrace.ext.test_visibility.api.Test.discover() acepta un objeto TestSourceFileInfo opcional como el parámetro source_file_info. Un objeto TestSourceFileInfo representa la ruta y, opcionalmente, las líneas de inicio y fin de una prueba determinada.

El método ddtrace.ext.test_visibility.api.TestSourceFileInfo() acepta tres parámetros posicionales:

  • path: un objeto pathlib.Path (hecho relativo a la raíz del repositorio por la API Test Optimization)
  • start_line: un número entero opcional que representa la línea de inicio de la prueba en el archivo
  • end_line: un número entero opcional que representa la línea de fin de la prueba en el archivo
Configuración de parámetros después del descubrimiento de pruebas

El método de clase ddtrace.ext.test_visibility.api.Test.set_parameters() acepta un objeto TestId como argumento, y una cadena analizable en JSON, para establecer el parameters para la prueba.

Nota: esto sobrescribe los parámetros asociados con la prueba, pero no modifica el campo TestId del objeto parameters.

Configurar parámetros después de que se haya descubierto una prueba requiere que el objeto TestId sea único incluso sin que el campo parameters esté definido.

Ejemplo de código

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()

Para configuraciones adicionales, consulte Configuración.

Configuración de ajustes

Para configurar el SDK, establezca las siguientes variables de entorno antes de iniciar el proceso de prueba. Para ejecutores de pruebas en paralelo, establézcalas en el proceso principal para que cada trabajador las herede.

DD_SERVICE (Opcional)
Nombre del servicio o biblioteca bajo prueba.
Predeterminado: El nombre del repositorio. Si no está disponible, test para pytest o unittest para unittest.
Ejemplo: my-python-app
DD_ENV (Opcional)
Nombre del entorno donde se ejecutan las pruebas.
Predeterminado: none
Ejemplos: local, ci
DD_CIVISIBILITY_AGENTLESS_ENABLED=true (Requerido para el modo Agentless)
Habilita el modo Agentless para enviar los resultados de las pruebas directamente a Datadog.
Predeterminado: false
DD_API_KEY (Requerido para el modo Agentless)
La clave de Datadog API utilizada para autenticar la carga de resultados de prueba. Esta variable no habilita el modo Agentless.
Predeterminado: (empty)
DD_SITE (Opcional para el modo Agentless)
El sitio de Datadog al cual cargar los resultados de las pruebas. Establezca esta configuración cuando utilice un sitio distinto a US1.
Predeterminado: datadoghq.com
DD_TRACE_AGENT_URL (Solo cuando se utiliza el Datadog Agent)
URL del Datadog Agent para la recopilación de trazas, en el formato http://hostname:port.
Predeterminado: http://localhost:8126
DD_TEST_SESSION_NAME (Opcional)
Identifica un grupo de pruebas, como unit-tests, integration-tests o smoke-tests.
Predeterminado: El nombre del trabajo de CI y el comando de prueba, o el comando de prueba si el nombre del trabajo de CI no está disponible.
Ejemplo: unit-tests, integration-tests, smoke-tests

Para obtener más información sobre las etiquetas reservadas service y env, consulte Unified Service Tagging.

También se pueden usar todas las demás opciones de Datadog Tracer configuration.

Recopilación de metadatos de 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

Mejores prácticas

Nombre de la sesión de prueba DD_TEST_SESSION_NAME

Use DD_TEST_SESSION_NAME para definir el nombre de la sesión de prueba y el grupo de pruebas relacionado. Ejemplos de valores para esta etiqueta serían:

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

Si no se especifica DD_TEST_SESSION_NAME, el valor predeterminado es el nombre del trabajo de CI y el comando de prueba. Si el nombre del trabajo de CI no está disponible, se utiliza el comando de prueba.

El nombre de la sesión de prueba debe ser único dentro de un repositorio para ayudarle a distinguir diferentes grupos de pruebas.

Cuándo usar DD_TEST_SESSION_NAME

Existe un conjunto de parámetros que Datadog verifica para establecer la correspondencia entre las sesiones de prueba. El comando de prueba utilizado para ejecutar las pruebas es uno de ellos. Si el comando de prueba contiene una cadena que cambia en cada ejecución, como una carpeta temporal, Datadog considera que las sesiones no están relacionadas entre sí. Por ejemplo:

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

Datadog recomienda usar DD_TEST_SESSION_NAME si sus comandos de prueba varían entre ejecuciones.

Limitaciones conocidas

Los complementos para pytest que alteran la ejecución de la prueba pueden causar un comportamiento inesperado.

Paralelización

Los complementos que introducen la paralelización en pytest (como pytest-xdist o pytest-forked) crean un evento de sesión para cada instancia paralelizada.

Existen varios problemas cuando estos complementos se utilizan junto con ddtrace, aunque se han resuelto para pytest-xdist en versiones recientes de dd-trace-py (3.12.6 y posteriores). Por ejemplo, una sesión, un módulo o una suite pueden aprobarse incluso cuando las pruebas individuales fallan. Asimismo, todas las pruebas pueden aprobarse y la suite/sesión/módulo fallar. Esto sucede porque estos complementos crean subprocesos de trabajo, y los spans creados en el proceso principal pueden no reflejar los resultados de los procesos secundarios. Por esta razón, el uso de ddtrace junto con pytest-forked no es compatible por el momento, mientras que pytest-xdist solo tiene soporte para ddtrace>=3.12.6.

Cada trabajador informa los resultados de las pruebas a Datadog de forma independiente, por lo que las pruebas del mismo módulo que se ejecutan en diferentes procesos generan eventos de módulo o suite separados.

El recuento total de eventos de prueba (y su exactitud) no se ve afectado. Los eventos individuales de sesión, módulo o suite pueden tener resultados inconsistentes con otros eventos en la misma ejecución de pytest (con pytest-forked).

Orden de las pruebas

Los complementos que cambian el orden de ejecución de la prueba (como pytest-randomly) pueden crear múltiples eventos de módulo o suite. La duración y los resultados de los eventos de módulo o suite también pueden ser inconsistentes con los resultados informados por pytest.

El recuento total de eventos de prueba (y su exactitud) permanece sin cambios.

En algunos casos, si la ejecución de la prueba unittest se realiza de manera paralela, esto puede interrumpir la instrumentación y afectar la optimización de las pruebas.

Datadog recomienda que utilice hasta un proceso a la vez para evitar afectar la optimización de las pruebas.

Lecturas adicionales