Logotipo de Parasoft

Obtenga más información sobre la prueba de Parasoft C/C++.

Únase a nuestra demostración mensual de productos de 30 minutos.

Regístrate Ahora

WEBINAR

Todo lo que necesita saber sobre la cobertura del código estructural para C y C++

La cobertura estructural es la identificación del código que se ha ejecutado y registrado. Hay varias razones por las que es importante realizar esta actividad para sistemas integrados de seguridad crítica. Una es determinar si el software ha sido probado adecuadamente. Otra es satisfacer los requisitos de cumplimiento y certificación. También es posible que desees asegurarte de que no haya ningún código inactivo en tu software.

Esta presentación profundiza en Cobertura de código estructural para el desarrollo en C y C++Se centrará en su importancia para los sistemas críticos de seguridad y explorará diversos criterios de medición, como la cobertura de declaraciones, ramas y MC/DC. También abordaremos métodos prácticos para lograr y automatizar la cobertura de código.

Le mostraremos la cobertura del código estructural para extractos, sucursales y MC/DC junto con informes automatizados y métricas para la cobertura y la complejidad del código.

Comprender la cobertura del código

La cobertura de código consiste en identificar qué partes de tu código se han ejecutado realmente durante las pruebas. Es una métrica clave para determinar si tu software se ha probado lo suficientemente exhaustivamente. Para sistemas embebidos críticos para la seguridad, esto es vital para el cumplimiento normativo y la certificación. Además, te ayuda a encontrar y eliminar código inactivo (código que nunca se ejecuta).

En esencia, la cobertura de código responde a la pregunta: "¿He realizado suficientes pruebas?". También ayuda a descubrir errores ocultos en secciones sin probar. La gran pregunta es: ¿quieres arriesgarte a esas áreas sin probar? En muchas industrias reguladas, puede que no tengas otra opción: podrías necesitar una cobertura del 100%.

Puntos clave

  • Propósito: Identificar el código ejecutado, garantizar las pruebas adecuadas, satisfacer el cumplimiento y encontrar el código inactivo.
  • Mecanismo: Generalmente se logra a través de la instrumentación de código, donde se agrega código adicional para registrar la ejecución.
  • Métrica: Los tipos comunes incluyen declaración, rama (decisión) y cobertura de condición/decisión modificada (MC/DC).
  • Normas: Industrias como la automotriz (ISO 26262), la aeroespacial (DO-178C) y la médica (IEC 62304) tienen requisitos de cobertura específicos basados ​​en los niveles de integridad de seguridad.
  • Automatización: Las herramientas pueden automatizar la generación de casos de prueba y el análisis de cobertura, integrándose en IDE y pipelines CI/CD.
  • Desafíos: Lograr una cobertura del 100% puede ser difícil debido al código defensivo o al código inalcanzable, que a menudo requiere una inspección visual (depurador) o un diseño de caso de prueba específico.

Aspectos destacados de la demostración

Durante la demostración, se muestran las capacidades clave:

  • Integración IDE: Visualizar métricas de cobertura directamente dentro de IDE como Eclipse y VS Code, mostrando cobertura de línea, declaración, rama y MC/DC.
  • Generación de pruebas automatizada: Generar pruebas unitarias que contribuyan a los objetivos de cobertura.
  • Cobertura de la aplicación (línea de comandos): Utilizar herramientas como C/C++test para instrumentar, crear y ejecutar pruebas en aplicaciones fuera del IDE, generando registros de cobertura que luego pueden importarse nuevamente a un IDE para su análisis.
  • Prueba de hardware de destino: Soporte para recopilar datos de cobertura en objetivos integrados, con opciones para optimizar el tamaño o la velocidad.
  • Panel de cobertura: Informes y análisis centralizados de datos de cobertura utilizando plataformas como DTP.

Cómo funciona la cobertura de código

La forma más común de obtener cobertura de código Se realiza mediante la instrumentación de código. Esto implica añadir pequeños fragmentos de código al código fuente original. Estas adiciones rastrean si se ha ejecutado una sentencia, decisión o rama. La instrumentación registra esta información, lo que permite a las herramientas calcular un porcentaje de cobertura y visualizar qué partes del código fueron afectadas.

Es posible que vea su código resaltado en verde (probado) con algunas partes en rojo (sin probar). Algunas herramientas muestran código parcialmente cubierto, a menudo en amarillo. Esto puede ocurrir con un if afirmación que tiene múltiples condiciones, donde no se probaron todos los resultados posibles de esas condiciones.

Tipos de cobertura estructural

Cuando hablamos de cobertura estructural, analizamos diferentes maneras de medir el grado de exhaustividad con el que se ha probado la estructura del código. Si bien los términos a veces pueden estar sobrecargados o interpretarse de forma diferente en diferentes industrias, los tipos principales para aplicaciones de C y C++ críticas para la seguridad son:

  • Cobertura de estado de cuenta: Asegura que cada declaración ejecutable en el código se haya ejecutado al menos una vez.
  • Cobertura de sucursal (o cobertura de decisión): Garantiza que cada rama posible (como la true y false resultados de una if declaración) ha sido ejecutada.
  • Cobertura de Condición/Decisión Modificada (MC/DC): Este es un estándar más riguroso, a menudo requerido para sistemas de alta seguridad. Garantiza que se haya demostrado de forma independiente que cada condición dentro de una decisión afecta el resultado de la misma. Para una decisión como... (A && B), MC/DC requiere pruebas que demuestren A cambiando el resultado mientras B es fijo, y B cambiando el resultado mientras A se arregla, además de probar todas las ramas.

Existen otros tipos, como la cobertura de condición (que prueba condiciones individuales) y la cobertura de línea (que garantiza la ejecución de cada línea, lo cual puede diferir de la cobertura de sentencia si varias sentencias se encuentran en una misma línea). Sin embargo, la sentencia, la rama y la MC/DC son las más citadas en las normas de seguridad.

Automatización de la cobertura del código

Determinar manualmente los casos de prueba exactos necesarios para alcanzar objetivos de cobertura específicos puede ser una tarea tediosa. Afortunadamente, existen herramientas que pueden ser de gran ayuda.

Asesor de cobertura Las funciones pueden analizar tu código y sugerir valores de parámetros específicos o precondiciones para que tus pruebas unitarias alcancen líneas o ramas específicas. Esto puede acelerar drásticamente la creación de casos de prueba.

Generación de casos de prueba unitaria automatizada Es otra potente función. Las herramientas pueden generar automáticamente un conjunto de pruebas unitarias diseñadas no solo para comprobar la funcionalidad, sino también para cumplir con los requisitos de cobertura estructural. Estas pruebas generadas suelen incluir varios tipos de comprobaciones, como pruebas de puntero nulo, pruebas de valor límite y pruebas de máximo intermedio, para detectar posibles errores y mejorar la cobertura.

Combinando la cobertura de diferentes métodos

Es raro que un solo método de prueba alcance una cobertura del 100 %, especialmente si el objetivo es alto. A continuación, se explica cómo combinar diferentes métodos:

  • Pruebas del sistema: Ejecutar las pruebas de sistema existentes contra código instrumentado puede cubrir gran parte de la aplicación con un mínimo esfuerzo adicional. Sin embargo, las pruebas de sistema a menudo pasan por alto rutas de código defensivo que solo se activan en condiciones de fallo (como corrupción de memoria o fallos de hardware), lo que suele resultar en una cobertura cercana al 60 %.
  • Examen de la unidad: Crear pruebas unitarias específicas es crucial para evaluar estas rutas de código defensivo u otros escenarios específicos que las pruebas de sistema pasan por alto. Al diseñar pruebas unitarias para condiciones específicas, puede aumentar significativamente su cobertura general.
  • Prueba manual: Incluso las pruebas manuales pueden contribuir a los datos de cobertura cuando se ejecutan en código instrumentado.

Las herramientas modernas permiten combinar los resultados de cobertura de estos diferentes métodos de prueba. Esto proporciona una visión consolidada de la cobertura total del código, cumpliendo así los requisitos de cumplimiento que permiten combinar métricas.

Manejar los desafíos

  • Código inalcanzable: A veces, el código puede estar estructurado de tal manera que resulta imposible acceder a él mediante pruebas normales (por ejemplo, un bucle infinito seguido de una sentencia de retorno). En estos casos, los estándares suelen permitir la cobertura mediante inspección. Esto significa que se puede confirmar visualmente que el código es inaccesible o usar herramientas de depuración para revisarlo paso a paso, documentando por qué se considera cubierto.
  • Hinchazón de código: La instrumentación a veces puede aumentar el tamaño del ejecutable, lo que podría impedir que encaje en un hardware de destino con recursos limitados. Una solución alternativa común es instrumentar la mitad del código, ejecutar pruebas, capturar la cobertura, desinstrumentar la primera mitad, instrumentar la segunda mitad, ejecutar pruebas y fusionar los resultados de la cobertura.
  • Cobertura del código de ensamblaje: Para los niveles de seguridad más altos (como DO-178C DAL A), podría requerirse un análisis de cobertura a nivel de ensamblado o de código objeto. Esto se debe a que los compiladores y enlazadores pueden generar código no trazable directamente al origen. Herramientas especializadas pueden automatizar el proceso de recopilación de cobertura estructural del código objeto ejecutable.

Integración de la cobertura en CI/CD

Para el desarrollo moderno, integrar la cobertura de código en su flujo de trabajo de Integración Continua/Entrega Continua (CI/CD) es clave. Las herramientas pueden instrumentar su aplicación durante el proceso de compilación, recopilar datos de cobertura sin procesar durante las pruebas automatizadas y luego generar informes sobre estos datos en su IDE o en un panel central (como la Plataforma de Pruebas de Desarrollo (DTP) de Parasoft).

Esto permite una retroalimentación continua sobre la calidad y el riesgo del código, lo que facilita una mejor toma de decisiones durante todo el ciclo de desarrollo. Las integraciones con herramientas de CI/CD populares, como Jenkins, GitLab y Azure DevOps, son comunes.

Conclusión

La cobertura del código estructural es una práctica crucial para garantizar la calidad, la seguridad y la fiabilidad del software, especialmente en sectores regulados. Al comprender los diferentes tipos de cobertura, aprovechar la automatización e integrar el análisis de cobertura en su flujo de trabajo de desarrollo, podrá cumplir eficazmente con los requisitos de cumplimiento normativo y desarrollar software más robusto.