If you are using auto-instrumentation for one of these providers, 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:
DD_CIVISIBILITY_AGENTLESS_ENABLED=true (Required)
Enables or disables Agentless mode. Default: false
DD_API_KEY (Required)
The Datadog API key used to upload the test results. Default: (empty)
Additionally, configure the Datadog site to which you want to send data.
DD_SITE (Required)
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.
Para activar la instrumentación de tests pytest, añade la opción --ddtrace al ejecutar pytest.
pytest --ddtrace
Si también quieres activar el resto de las integraciones de APM para obtener más información en tu gráfico de llamas, añade la opción --ddtrace-patch-all:
pytest --ddtrace --ddtrace-patch-all
Para ver configuraciones adicionales, consulta Configuración.
Añadir etiquetas (tags) personalizadas a tests
Para añadir etiquetas personalizadas a tus tests, declara ddspan como un argumento en tu test:
fromddtraceimporttracer# Declare `ddspan` as argument to your testdeftest_simple_case(ddspan):# Set your tagsddspan.set_tag("test_owner","my_team")# test continues normally# ...
Para crear filtros o campos group by para estas etiquetas, debes primero crear facetas. Para obtener más información sobre cómo añadir etiquetas, consulta la sección Añadir etiquetas en la documentación de instrumentación de Python.
Añadir medidas personalizadas a tests
Al igual que con las etiquetas, para añadir medidas a tus tests, utiliza el tramo (span) activo actual:
fromddtraceimporttracer# Declare `ddspan` as an argument to your testdeftest_simple_case(ddspan):# Set your tagsddspan.set_tag("memory_allocations",16)# test continues normally# ...
Para instrumentar tus tests de referencia con pytest-benchmark, ejecuta tus tests de referencia con la opción --ddtrace cuando se ejecuta pytest y Datadog detecta métricas desde pytest-benchmark automáticamente:
Para ver configuraciones adicionales, consulta Configuración.
API de test manual
Nota: La API de test manual de Test Optimization está en fase beta y puede sufrir modificaciones.
A partir de la versión 2.13.0, el rastreador Python de Datadog proporciona la API de Test Optimization (ddtrace.ext.test_visibility) para enviar resultados de optimización de tests 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 optimización de tests.
La ejecución de tests tiene dos fases:
Descubrimiento: informar a la API sobre los elementos que puede esperar
Ejecución: enviar los resultados (mediante llamadas de inicio y fin)
Las distintas fases de descubrimiento y ejecución permiten que haya un intervalo entre que el proceso del ejecutor de tests recopila los tests y éstos comienzan.
Los usuarios de la API deben proporcionar identificadores coherentes (descritos a continuación) que se utilizan como referencias para los elementos de Test Optimization dentro del almacenamiento de estados de la API.
Activar test_visibility
Debes llamar a la función ddtrace.ext.test_visibility.api.enable_test_visibility() antes de utilizar la API de Test Optimization.
Llama a la función ddtrace.ext.test_visibility.api.disable_test_visibility() antes de que el proceso termine para asegurarte de que los datos se vacíen correctamente.
Modelo de dominio
La API se basa en cuatro conceptos: sesión de tests, módulo de test, conjuntos de tests y tests.
Los módulos, paquetes y tests conforman una jerarquía en la API de optimización de tests de Python, representada por la relación de superioridad del identificador de elemento.
Sesión de tests
Una sesión de test representa la ejecución del test de un proyecto, que suele corresponder a la ejecución de un comando de test. Sólo se puede detectar, iniciar y finalizar una sesión en la ejecución del programa de Test Optimization.
Llama a ddtrace.ext.test_visibility.api.TestSession.discover() para detectar la sesión, pasando el comando del test, un nombre de marco de trabajo determinado y la versión.
Llama a ddtrace.ext.test_visibility.api.TestSession.start() para iniciar la sesión.
Una vez finalizados los tests, llama a ddtrace.ext.test_visibility.api.TestSession.finish().
Módulo de test
Un módulo de test representa una unidad de trabajo más pequeña dentro de la ejecución de tests de un proyecto (un directorio, por ejemplo).
Llama a ddtrace.ext.test_visibility.api.TestModuleId() y proporciona el nombre del módulo como parámetro para crear un TestModuleId.
Llama a ddtrace.ext.test_visibility.api.TestModule.discover() y pasa el objeto TestModuleId como argumento para detectar el módulo.
Llama a ddtrace.ext.test_visibility.api.TestModule.start() y pasa el objeto TestModuleId como argumento para iniciar el módulo.
Después de que se hayan completado todos los elementos secundarios dentro del módulo, llama a ddtrace.ext.test_visibility.api.TestModule.finish() y pasa el objeto TestModuleId como argumento.
Conjunto de tests
Un paquete de tests representa un subconjunto de tests dentro de los módulos de un proyecto (archivo.py, por ejemplo).
Llama a ddtrace.ext.test_visibility.api.TestSuiteId() y proporciona el TestModuleId del módulo principal y el nombre del paquete como argumentos para crear un TestSuiteId.
Llama a ddtrace.ext.test_visibility.api.TestSuite.discover() y pasa el objeto TestSuiteId como argumento para detectar el paquete.
Llama a ddtrace.ext.test_visibility.api.TestSuite.start() y pasa el objeto TestSuiteId como argumento para iniciar el paquete.
Después de que se hayan completado todos los elementos secundarios dentro del paquete, llama a ddtrace.ext.test_visibility.api.TestSuite.finish() y pasa el objeto TestSuiteId como argumento.
Test
Un test representa un único caso de test que se ejecuta como parte de un paquete de tests.
Llama a ddtrace.ext.test_visibility.api.TestId() y proporciona el TestSuiteId del paquete principal y el nombre del test como argumentos para crear un TestId. El método TestId() acepta una cadena analizable JSON como argumento opcional parameters. El argumento parameters puede utilizarse para distinguir tests parametrizados que tienen el mismo nombre, pero diferentes valores de parámetros.
Llama a ddtrace.ext.test_visibility.api.Test.discover() y pasa el objeto TestId como argumento para detectar el test. El método de clase Test.discover() acepta una cadena como parámetro opcional resource , que por defecto es el name del TestId.
Llama a ddtrace.ext.test_visibility.api.Test.start() y pasa el objeto TestId como argumento para iniciar el test.
Llama a ddtrace.ext.test_visibility.api.Test.mark_pass() y pasa el objeto TestId como argumento para indicar que el test fue exitoso.
Llama a ddtrace.ext.test_visibility.api.Test.mark_fail() y pasa el objeto TestId como argumento para indicar que el test falló. mark_fail() acepta un objeto opcional TestExcInfo como parámetro exc_info.
Llama a ddtrace.ext.test_visibility.api.Test.mark_skip() y pasa el objeto TestId como argumento para indicar que el test fue omitido. mark_skip() acepta una cadena opcional como parámetro skip_reason.
Información de 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 un test.
El método ddtrace.ext.test_visibility.api.TestExcInfo() toma tres parámetros de posición:
exc_type: tipo de excepción encontrada
exc_value: objeto BaseException de la excepción
exc_traceback: objeto Traceback de la excepción
Información sobre el propietario del código
El método de clase ddtrace.ext.test_visibility.api.Test.discover() acepta una lista opcional de cadenas como parámetro codeowners.
Información del archivo fuente del test
El método de clase ddtrace.ext.test_visibility.api.Test.discover() acepta un objeto opcional TestSourceFileInfo como parámetro source_file_info. Un objeto TestSourceFileInfo representa la ruta y, opcionalmente, las líneas de inicio y fin de un test determinado.
El método ddtrace.ext.test_visibility.api.TestSourceFileInfo() acepta tres parámetros de posición:
path: objeto pathlib.Path (hecho relativo a la raíz del repositorio por la API Test Optimization )
start_line: entero opcional que representa la línea de inicio del test en el archivo
end_line: entero opcional que representa la línea de fin del test en el archivo
Definición de parámetros tras la detección de un test
El método de clase ddtrace.ext.test_visibility.api.Test.set_parameters() acepta un objeto TestId como argumento y una cadena analizable JSON para definir los parameters del test.
Nota: Esta acción sobrescribe los parámetros asociados al test, pero no modifica el campo parameters del objeto TestId.
La definición de parámetros tras la detección de un test requiere que el objeto TestId sea único, incluso sin haber configurado el campo parameters.
Ejemplo de código
fromddtrace.ext.test_visibilityimportapiimportpathlibimportsysif__name__=="__main__":# Enable the Test Optimization serviceapi.enable_test_visibility()# Discover itemsapi.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 filetest_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 itemsapi.TestSession.start()api.TestModule.start(test_module_1_id)api.TestSuite.start(test_suite_1_id)# test_1 passes successfullyapi.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 infoapi.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 skippedapi.Test.start(test_3_id)api.Test.mark_skip(test_3_id,skip_reason="example skipped test")# test_4 fails, and attaches exception infoapi.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 modulesapi.TestSuite.finish(test_suite_1_id)api.TestModule.finish(test_module_1_id)api.TestSession.finish()
La siguiente es una lista de los parámetros de configuración más importantes que puedes utilizar con el rastreador, ya sea mediante código o mediante variables de entorno:
DD_TEST_SESSION_NAME
Identifica un grupo de tests, como integration-tests, unit-tests o smoke-tests. Variable de entorno: DD_TEST_SESSION_NAME Por defecto: (nombre del trabajo CI + comando de test) Ejemplo: unit-tests, integration-tests, smoke-tests
DD_SERVICE
Nombre del servicio o de la biblioteca en proceso de test. Variable de entorno: DD_SERVICE Por defecto: pytest Ejemplo: my-python-app
DD_ENV
Nombre del entorno en el que se ejecutan los tests. **Variable de entorno **: DD_ENV Por defecto: none Ejemplos: local, ci
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
Prácticas recomendadas
Nombre de la sesión de test DD_TEST_SESSION_NAME
Utiliza DD_TEST_SESSION_NAME para definir el nombre de la sesión de test y del grupo de tests relacionado. Algunos ejemplos de valores de 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 por defecto utilizado es una combinación de:
Nombre del trabajo CI
Comando utilizado para ejecutar los tests (como pytest --ddtrace)
El nombre de la sesión de test debe ser único dentro de un repositorio para ayudar a distinguir diferentes grupos de tests.
Cuándo utilizar DD_TEST_SESSION_NAME
Hay un conjunto de parámetros que Datadog comprueba para establecer la correspondencia entre las sesiones de test. El comando de test utilizado para ejecutar los tests es uno de ellos. Si el comando de test 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:
Datadog recomienda utilizar DD_TEST_SESSION_NAME si tus comandos de test varían entre ejecuciones.
Limitaciones conocidas
Los complementos para pytest que alteran la ejecución de los tests pueden provocar comportamientos inesperados.
Paralelización
Los complementos que introducen una 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. Por ejemplo, una sesión, un módulo o un paquete pueden pasar aunque fallen los tests individuales. Del mismo modo, todos los tests pueden pasar, pero el paquete, la sesión o el módulo pueden fallar. Esto ocurre porque estos complementos crean subprocesos de Worker y los tramos creados en el proceso principal pueden no reflejar los resultados de los procesos secundarios. Por esta razón, no se admite el uso de ddtrace junto con pytest-xdist y pytest-forked por el momento.
Cada Worker informa de los resultados de los tests a Datadog de forma independiente, por lo que los tests del mismo módulo que se ejecutan en diferentes procesos generan eventos de módulos o paquete separados.
El recuento global de eventos de tests (y su corrección) no se ve afectado. Los eventos de sesión individual, módulo o paquete pueden tener resultados incompatibles con otros eventos en la misma ejecución pytest.
Solicitudes de tests
Los complementos que cambian el orden de ejecución de los tests (como pytest-randomly) pueden crear varios eventos de módulo o conjunto. La duración y los resultados de los eventos de módulo o conjunto también pueden ser incoherentes con los resultados informados por pytest.
El número total de eventos de test (y su corrección) no se ven afectados.
En algunos casos, si la ejecución de tu test unittest se realiza de forma paralela, esto puede romper la instrumentación y afectar a la optimización del test.
Datadog recomienda utilizar un máximo de un único proceso a la vez para no afectar a la optimización de los tests.