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

Lo que necesita saber sobre la cobertura de código para sistemas C/C++ integrados

La cobertura de código mide la proporción del código fuente de una aplicación que se prueba mediante diversos métodos, como pruebas unitarias, pruebas manuales y pruebas funcionales automatizadas. Los objetivos de porcentaje de cobertura de código pueden ser subjetivos. La exhaustividad de la cobertura en sistemas críticos para la seguridad depende de la métrica del nivel de integridad de seguridad de la aplicación (SIL) utilizada en diferentes industrias y del nivel de garantía de diseño (DAL) comúnmente utilizado en aviónica. En la construcción de aplicaciones críticas para la seguridad donde un fallo puede causar la muerte, las normas regulatorias y del sector exigen una cobertura del código estructural del 100 %.

Esta presentación profundiza en el tema esencial de la cobertura de código para sistemas C/C++ embebidos, explicando su importancia, los diferentes tipos de medición y su aplicación práctica. Exploramos cómo lograr pruebas exhaustivas, especialmente en entornos críticos para la seguridad, y mostramos herramientas que simplifican el proceso.

Comprender la cobertura del código

La cobertura de código es una métrica que indica cuánto del código fuente de tu aplicación se ha ejecutado durante las pruebas. Es una forma de responder a la pregunta: "¿Hemos probado lo suficiente?". Al destacar el código no probado, se ayuda a descubrir posibles errores e identificar código inactivo. La forma más común de lograr esto es mediante la instrumentación de código, donde se añade código adicional para rastrear la ejecución de sentencias, decisiones o ramas. Esta instrumentación registra la ejecución, lo que permite calcular y visualizar un porcentaje de la cobertura de código, a menudo con el código resaltado en verde (ejecutado) o rojo (no ejecutado).

Criterios clave de cobertura

  • Cobertura de estado de cuenta: Asegura que cada declaración en la aplicación haya sido ejecutada.
  • Cobertura de línea: Comprueba si se ha ejecutado cada línea de código. El resultado puede diferir de la cobertura de sentencias si existen varias sentencias en una sola línea.
  • Cobertura de sucursal (cobertura de decisión): Verifica que cada posible ruta de ejecución después de un punto de decisión (como una sentencia if) se ejecute al menos una vez. Esto incluye asegurar que se prueben tanto los resultados verdaderos como los falsos de las condiciones.
  • Cobertura de Condición/Decisión Modificada (MC/DC): Un estándar más riguroso, especialmente para sistemas críticos para la seguridad. MC/DC exige que se haya demostrado que cada condición de una decisión afecta independientemente su resultado. Esto implica probar todos los resultados posibles para cada condición y garantizar que cada condición pueda modificar el resultado de la decisión.
  • Cobertura de Condiciones Múltiples (MCC): Prueba todas las combinaciones posibles de resultados para las condiciones dentro de las decisiones. Si bien es exhaustivo, puede generar un número muy elevado de casos de prueba.

Aspectos destacados de la demostración práctica

La presentación incluyó una demostración que mostró:

  • Generación automatizada de casos de prueba unitaria: Las herramientas pueden generar automáticamente numerosas pruebas unitarias para ayudar a alcanzar los objetivos de cobertura.
  • Análisis de cobertura: Visualizar métricas de cobertura (línea, declaración, rama, MC/DC) dentro de IDE como Eclipse, VS Code o mediante herramientas de línea de comandos independientes.
  • Cobertura de la aplicación: Utilizar herramientas de línea de comandos para instrumentar y recopilar datos de cobertura para aplicaciones independientes, que luego pueden importarse a una IDE para su análisis.
  • Prueba de hardware de destino: La capacidad de realizar análisis de cobertura en objetivos integrados, con optimizaciones de tamaño y velocidad, y soporte para aplicaciones multiproceso.
  • Presentación de informes: Generar informes y publicar datos de cobertura en plataformas como DTP (Plataforma de pruebas de desarrollo) para análisis y paneles de control centralizados.

Por qué son importantes los tipos de cobertura específicos en los sistemas integrados

En el mundo embebido, C y C++ se utilizan con frecuencia en sistemas críticos para la seguridad. Industrias como la automotriz (ISO 26262), la aviónica (DO-178C) y los dispositivos médicos (IEC 62304) tienen estrictos requisitos regulatorios y estándares de proceso. Estos estándares suelen asignar Niveles de Integridad de Seguridad (SIL) o Niveles de Garantía de Diseño (DAL) a los componentes de software. Los niveles más altos, que indican un mayor riesgo si el software falla, suelen exigir pruebas más rigurosas. Por ejemplo, SIL 4 en IEC 61508 recomienda encarecidamente una cobertura del 100% para declaraciones, ramas y MC/DC. El denominador común de estos estándares es el enfoque en la cobertura de declaraciones, ramas y MC/DC, ya que los expertos del sector las consideran las mejores prácticas para garantizar un código de alta calidad, seguro y confiable.

Métodos para obtener cobertura de código

Lograr la cobertura del código Se puede realizar mediante varios métodos de prueba:

  • Pruebas del sistema: Ejecutar casos de prueba del sistema existente contra código instrumentado puede proporcionar una parte significativa de la cobertura con un mínimo esfuerzo adicional. Sin embargo, a menudo no alcanza el 100 %, especialmente en código defensivo que solo se ejecuta en condiciones de fallo.
  • Examen de la unidad: La creación de pruebas unitarias específicas puede apuntar al código no cubierto, incluido el código defensivo o ramas específicas, para alcanzar objetivos de cobertura más altos.
  • Prueba manual: Si bien es menos automatizada, la ejecución manual de pruebas también puede contribuir a las métricas de cobertura.

Muchas organizaciones combinan los resultados de estos diferentes métodos de prueba para alcanzar sus objetivos de cobertura general. Por ejemplo, la cobertura de las pruebas unitarias puede combinarse con la de las pruebas del sistema.

Integración de la cobertura en CI/CD

La cobertura de código es fundamental en una canalización de Integración Continua/Entrega Continua (CI/CD). Las herramientas pueden automatizar la instrumentación, la ejecución y la generación de informes de los datos de cobertura, integrándose a la perfección con sistemas de compilación y plataformas de CI/CD como Jenkins, GitLab y Azure DevOps. Esto proporciona información en tiempo real sobre la calidad del código y ayuda a gestionar los riesgos eficazmente.

Manejo de desafíos en la cobertura del código

  • Código inalcanzable: A veces, debido a bucles infinitos o estructuras de código específicas, es posible que ciertas sentencias sean imposibles de alcanzar mediante pruebas normales. En tales casos, cobertura por inspección (verificar visualmente la ejecución, generalmente a través de la depuración) es un enfoque recomendado para satisfacer los estándares.
  • Hinchazón de código: La instrumentación puede aumentar el tamaño del ejecutable. Si esto impide que la aplicación se adapte al hardware de destino, una práctica común es instrumentar la mitad del código, recopilar la cobertura, instrumentar la otra mitad y fusionar los resultados.
  • Cobertura a nivel de ensamblaje: Para sistemas de alta seguridad (como DO-178C Nivel A), se requiere cobertura a nivel de ensamblado o de código objeto, ya que los compiladores pueden generar código no trazable directamente al origen. Existen herramientas para automatizar este proceso.

En definitiva, la cobertura de código es una técnica eficaz para garantizar la calidad y la fiabilidad de los sistemas C/C++ embebidos, especialmente en ámbitos críticos para la seguridad. Al comprender los diferentes criterios de cobertura y utilizar las herramientas adecuadas, los equipos de desarrollo pueden alcanzar sus objetivos de prueba con mayor eficiencia.