Seminario web destacado: Pruebas de API mejoradas con IA: un enfoque de prueba sin código | Vea ahora

Cómo obtener una cobertura del código estructural del 100% de los sistemas críticos para la seguridad

Foto de cabeza de Ricardo Camacho, Director de Cumplimiento de Seguridad y Seguridad
Marzo 7, 2023
7 min leer

Obtener la cobertura del código estructural de los sistemas es una de las cosas cruciales que todo desarrollador de software e ingeniero de calidad debe saber. Siga leyendo para comprender la cobertura del código estructural y por qué es fundamental para las pruebas de software.

Muchos ingenieros de desarrollo y verificación de software no comprenden realmente por qué es importante obtener una cobertura estructural. Muchos simplemente lo hacen porque lo exige el estándar funcional de su industria y no lo toman en serio.

Los sistemas críticos para la seguridad como ADAS pueden transportar pasajeros sin un conductor, permitir que los pilotos automáticos vuelen a las personas a través de nuestros cielos y mantener vivos a los pacientes con dispositivos médicos. La vida de las personas depende de estos sistemas. es vital para obtener cobertura de código estructural. Examinemos qué es la cobertura estructural y más razones por las que es importante.

¿Qué es la cobertura estructural?

En pocas palabras, la cobertura estructural es la identificación del código que se ha ejecutado y registrado con el fin de determinar si el sistema se ha probado adecuadamente. La minuciosidad de la cobertura en sistemas críticos para la seguridad depende del nivel de integridad de seguridad (SIL). ASIL en la industria automotrizy el nivel de garantía de desarrollo (DAL) comúnmente utilizado en aviónica.

Por minuciosidad, me refiero a los elementos estructurales en el código. En los sistemas embebidos, estos generalmente se desglosan en la declaración de código, la rama, las decisiones de condición modificada y también puede profundizar en un nivel mucho más fino de granularidad, como el código objeto o el lenguaje ensamblador.

Es posible que escuche o lea sobre otros tipos de métricas de cobertura como función, llamada, bucle, condición, salto, decisión, etc. Pero para los sistemas integrados de seguridad crítica, todo lo que necesita saber actualmente es la declaración, la rama, MC / DC y el código de objeto. Los otros tipos mencionados son un subconjunto y, por lo tanto, se abordan.

Actualmente existe un movimiento hacia la adopción de la Cobertura de Condiciones Múltiples (MCC), que es más completa que MC / DC. MCC requiere un número mucho mayor de casos de prueba: 2 a la potencia del número de condiciones.

La fórmula: 2C

Dado que MCC no está oficialmente recomendado ni exigido por los estándares de procesos de la industria ISO 26262, DO-178, CEI 62304, CEI 61508 or ES 50128, No lo cubriré en esta publicación de blog.

Cobertura de declaraciones y sucursales

La cobertura de la declaración es la tarea más simple y representa cada línea de código en un programa. Sin embargo, las declaraciones de código pueden tener distintos grados de complejidad. Por ejemplo, una declaración de rama representa una si entonces más condición en el código. Declaraciones como caso o interruptor se interpretan como una rama. Aún así, si desea obtener cobertura para las sucursales, esto significa que debe cubrirse la ejecución de las rutas de decisión tanto verdaderas como falsas.

El diagrama de flujo con un círculo azul en la parte superior, la condición verdadera a la izquierda apunta a A, la condición falsa a la derecha apunta a B. Una línea conecta A con B que apunta a otro círculo azul oscuro dentro de un círculo azul más grande.
Diagrama de flujo de rama

Cuando los niveles de seguridad más altos sean motivo de preocupación, es posible que se requiera una cobertura de decisión de condición modificada (MC / DC). Las ramas pueden crecer en complejidad, donde hay múltiples condiciones en una decisión y cada condición debe probarse de forma independiente.

Para los criterios de cobertura, esto significa que se ha demostrado que cada condición en la decisión afecta de forma independiente el resultado de esa decisión. Se puede utilizar una tabla de verdad para ayudar a realizar este análisis, como se muestra a continuación.

Además, cada condición en una decisión en el programa ha tomado todos los resultados posibles al menos una vez, y cada decisión en el programa ha tomado todos los resultados posibles al menos una vez.

En el siguiente ejemplo con 4 declaraciones de condición, hay 16 casos de prueba posibles. MC / DC requiere solo 5 para este ejemplo. Tome el número de condiciones y agregue 1.

La fórmula: (C + 1)

Tabla con encabezados de columna Caso de prueba n grados, C1, C2, C3, C4 y Decisión / Resultado en la parte superior. Debajo del encabezado del caso de prueba n grados están las filas 1-16. T o F llena el resto de las celdas de la tabla.
Tabla de verdad de decisiones de MC / DC para "Si (((a == 0) || (b <5)) && ((c> 7) || (d == 0)))" Posicionamiento

Cobertura de código de objeto

Para las aplicaciones críticas de seguridad más estrictas, como en aviónica, el estándar de proceso DO-178B / C Nivel A exige Cobertura de código de objeto. Esto se debe al hecho de que un compilador o vinculador genera código adicional que no se puede rastrear directamente a las declaraciones del código fuente. Por lo tanto, se debe realizar una cobertura a nivel de ensamblaje.

Imagínese el rigor y el coste laboral de tener que realizar esta tarea. Afortunadamente, existe Parasoft ASMTools, una solución automatizada para obtener cobertura de código objeto.

Captura de pantalla de la cobertura del código en lenguaje ensamblador de Parasoft ASMTools con una lista de pruebas y porcentaje de cobertura a la izquierda. A la derecha está el código. Algunos resaltados en verde, algunos en rosa, una línea en amarillo.
Cobertura del código de lenguaje ensamblador de Parasoft ASMTools

Obtención de cobertura de código

La cobertura del código suele identificarse mediante la instrumentación del código. Instrumentado se refiere a tener el código de usuario adornado con código adicional para determinar durante la ejecución si esa instrucción, rama o MC / CD se ha ejecutado.

Según el objetivo o dispositivo integrado, los datos de cobertura pueden almacenarse en el sistema de archivos, escribirse en la memoria o enviarse a través de varios canales de comunicación, como el puerto serie, el puerto TCP / IP, USB e incluso JTAG.

Instrumentación parcial

Tenga en cuenta que la instrumentación del código provoca que el código se sobrecargue y este aumento en el tamaño del código puede afectar la capacidad de cargar el código en su hardware de destino con restricciones de memoria para realizar pruebas.

La solución es instrumentar parte del código.

  1. Ejecute sus pruebas y capture la cobertura.
  2. Instrumentar la otra parte del código.
  3. Ejecute sus pruebas de nuevo.
  4. Captura la cobertura.
  5. Fusionar la cobertura de la ejecución de prueba anterior.

En función de las limitaciones de su objetivo, es de esperar que no tenga que atravesar demasiadas particiones instrumentadas. Tener que volver a ejecutar las mismas pruebas una y otra vez puede llevar mucho tiempo y ser costoso. Para mencionar rápidamente, también puede haber efectos de mala sincronización y rendimiento que la instrumentación puede causar.

Obtención de cobertura de código para sistemas integrados de seguridad y protección críticos

Analicemos cómo las organizaciones obtienen cobertura de código para sus sistemas de seguridad integrados y críticos.

Para los requisitos de cobertura del código, como una estructura obligatoria del 100%, una sucursal y una cobertura MC / DC, o un 80% opcional y personalmente deseado, existen varios métodos de prueba que se utilizan para alcanzar sus objetivos. Los métodos más comunes:

  • Prueba del sistema
  • Prueba unitaria
  • Prueba manual

Es típico combinar las métricas de cobertura de estas diversas prácticas. Pero, ¿cómo se identifica exactamente la cobertura del código?

Cobertura de las pruebas del sistema

Obtener cobertura de código a través de las pruebas del sistema es un método excelente para determinar si se han realizado suficientes pruebas. El enfoque es ejecutar todas las pruebas de su sistema y luego examinar qué partes del código no se han ejercido.

El código no ejecutado implica que es posible que se necesiten nuevos casos de prueba para ejercitar el código intacto donde un defecto puede estar al acecho, y ayuda a responder la pregunta, ¿he realizado suficientes pruebas?

Cuando he actuado cobertura de código durante las pruebas del sistema, la métrica resultante promedio es una cobertura del 60%. Gran parte del 40% del código no ejecutado se debe al código defensivo de su aplicación.

Lo que quiero decir con defensivo es código que solo se ejecutará cuando el sistema entre en un estado de falla o problemático que puede ser difícil de producir. Condiciones como pérdida de memoria, corrupción u otro tipo de falla causada por fallas de hardware pueden tardar semanas, meses o años en aparecer.

También existe un código defensivo exigido por sus pautas de codificación que las pruebas del sistema nunca pueden ejecutar. Por estas razones, las pruebas del sistema no pueden llevarlo a una cobertura del código estructural del 100%. Deberá emplear otros métodos de prueba como pruebas manuales y / o unitarias para llegar al 100%.

Tenga en cuenta que los estándares de proceso permiten la fusión de métricas de cobertura obtenidas de varios métodos de prueba.

Cobertura de las pruebas unitarias

Como se mencionó, Las pruebas unitarias se pueden utilizar como un enfoque complementario a las pruebas del sistema. en la obtención del 100% de cobertura. Obtener cobertura de código a través de pruebas unitarias es uno de los métodos más populares utilizados, pero no expone si ha realizado suficientes pruebas del sistema porque el enfoque está en el nivel de unidad (función/procedimiento).

El objetivo aquí es crear un conjunto de casos de prueba de unidad que ejerciten toda la unidad en la necesidad de cumplimiento de cobertura requerida (declaración, sucursal y MC / DC) para alcanzar el 100% de cobertura para esa unidad única. Esto se repite para cada unidad hasta que se cubre toda la base del código. Sin embargo, para aprovechar al máximo las pruebas unitarias, no se centre únicamente en obtener cobertura de código. Eso generalmente se puede lograr a través de casos de prueba de escenarios de días soleados.

Realmente ejercite la unidad en escenarios de días soleados y lluviosos, garantizando robustez, seguridad y bajo nivel trazabilidad de requisitos. Deje que la cobertura del código sea un biproducto de sus casos de prueba y complete la cobertura donde sea necesario.

Para ayudar a agilizar la cobertura del código a través de pruebas unitarias, existen capacidades de generación de casos de prueba configurables y automatizadas en Parasoft C / C ++test. Los casos de prueba se pueden generar automáticamente para probar el uso de punteros nulos, rangos mínimo-medio-máximo, valores de límite y mucho más. Esta automatización puede llevarlo lejos. En minutos, obtendrá una cantidad sustancial de cobertura de código.

Sin embargo, al igual que en las pruebas de sistemas, es difícil obtener una cobertura de código del 100% debido al uso de código defensivo o semántica de lenguaje formal. En el nivel granular de una unidad, el código defensivo puede venir en forma de tu préstamo estudiantil declaración en un cambiar. Si todos los casos posibles en un cambiar es capturado, esto deja el tu préstamo estudiantil declaración inalcanzable. En el siguiente ejemplo, el 0 regresar; nunca será ejecutado porque el mientras que (1) es infinito.

Captura de pantalla de un retorno inalcanzable 0; declaración
Inalcanzable 0 regresar; Posicionamiento

Entonces, ¿cómo se obtiene una cobertura del 100% para estos casos especiales?

Respuesta: Es necesario implementar métodos manuales.

El usuario puede etiquetar o anotar la declaración como cubierta usando un depurador, modificar la pila de llamadas y ejecutar la 0 regresar; declaración. Sea testigo visual de la ejecución y, como mínimo, documente el nombre del archivo, la línea de código y la declaración del código que ahora se considera cubierto.

Esta cobertura realizada mediante inspección manual/visual e informes se puede utilizar para complementar la cobertura capturada mediante pruebas unitarias. La adición de ambos informes de cobertura se puede utilizar para demostrar una cobertura del código estructural del 100%.

Cobertura integral del código: cobertura agregada en todas las prácticas de prueba

Si se llevó a cabo la cobertura de prueba del sistema y se va a incluir, los tres informes de cobertura (sistema, unidad, manual) se pueden usar para mostrar y demostrar el 100% de cobertura y cumplimiento.

Captura de pantalla del panel de Parasoft Report Center que muestra informes de cobertura de la aplicación en forma de tablas, gráficos y círculos porcentuales
DTP de Parasoft Ejemplo de informe de cobertura de código de panel

Resum

La cobertura del código estructural puede ayudar a responder la pregunta: ¿He realizado suficientes pruebas?

También puede ser un requisito de cumplimiento que deba cumplir. El objetivo de obtener cobertura de código es un medio adicional para ayudar a garantizar la seguridad, protección y confiabilidad del código. Muestra prueba de que se han realizado las pruebas. Y a través de esta prueba, se han identificado defectos.

Un defecto común que la cobertura de código puede identificar fácilmente, que no se mencionó en las secciones anteriores, es el descubrimiento de código inactivo. El código muerto es un código que no se llama ni se invoca de ninguna manera. Es un código que probablemente se quedó atrás debido a un cambio en los requisitos o que se olvidó accidentalmente.

La cobertura también se puede lograr a través de varios métodos de prueba (sistema, unidad, integración, manual, API). La cobertura acumulada de estos métodos se puede combinar para demostrar una cobertura de código del 100%.

También hay varios niveles de cobertura (declaración, sucursal, MC / DC y código de objeto) que es posible que deba realizar cuando los criterios se basan en su nivel SIL, ASIL o DAL. Afortunadamente, Parasoft ofrece soluciones de prueba de software automatizadas y los métodos que necesita abordar para obtener una cobertura de código estructural del 100%.

Vea cómo puede aprovechar las técnicas de análisis de código para su proyecto integrado. Ver el vídeo.

Obtenga comentarios críticos sobre la integridad y minuciosidad de su proceso de prueba con la prueba Parasoft C / C +.

Publicación relacionada + Recursos

Demostración de prueba de software C y C++
Seminarios Web
Regístrate ahora: 18 de diciembre

Demostración con preguntas y respuestas: Pruebas de software C y C++

Texto de demostración de prueba continua de C y C++ a la izquierda con el logotipo CT de prueba de Parasoft C/C++ a la derecha
Seminarios Web
Regístrate ahora: 20 de noviembre

Demostración con preguntas y respuestas: pruebas continuas de C y C++