Pregunta Código de Prueba de Unidad C [cerrado]


Este verano trabajé en un sistema integrado escrito directamente en C. Era un proyecto existente que la empresa para la que trabajo se había hecho cargo. Me he acostumbrado bastante a escribir pruebas unitarias en Java utilizando JUnit, pero me faltaba la mejor manera de escribir pruebas unitarias para el código existente (que necesitaba refactorización), así como para el nuevo código agregado al sistema.

¿Hay alguna manera de hacer pruebas unitarias de código C simple tan fácil como probar un código Java con, por ejemplo, JUnit? Cualquier idea que se aplique específicamente al desarrollo integrado (compilación cruzada a la plataforma arm-linux) sería muy apreciada.


714


origen


Respuestas:


Un marco de prueba de unidad en C es Comprobar; una lista de marcos de pruebas unitarias en C se puede encontrar aquí y se reproduce a continuación. Dependiendo de la cantidad de funciones de biblioteca estándar que tenga su tiempo de ejecución, puede o no puede usar una de ellas.

AceUnit

AceUnit (Advanced C y Embedded Unit) se anuncia a sí mismo como un marco de prueba de unidad de código C cómodo. Intenta imitar JUnit 4.x e incluye capacidades similares a reflexiones. AceUnit se puede usar en entornos de restricción de recursos, p. desarrollo de software integrado, y lo que es más importante, funciona bien en entornos en los que no se puede incluir un solo archivo de encabezado estándar y no se puede invocar una única función C estándar de las bibliotecas ANSI / ISO C. También tiene un puerto de Windows. No utiliza tenedores para atrapar señales, aunque los autores han expresado interés en agregar dicha característica. Ver el Página principal de AceUnit.

GNU Autounit

Muy similar a Check, que incluye bifurcar para ejecutar pruebas unitarias en un espacio de direcciones separado (de hecho, el autor original de Check tomó prestada la idea de GNU Autounit). GNU Autounit utiliza exhaustivamente GLib, lo que significa que los enlaces y los que necesitan opciones especiales, pero esto puede no ser un gran problema para usted, especialmente si ya está utilizando GTK o GLib. Ver el Página de inicio de GNU Autounit.

cUnit

También usa GLib, pero no se bifurca para proteger el espacio de direcciones de las pruebas unitarias.

CUnit

Estándar C, con planes para una implementación de GUI de Win32. Actualmente, no bifurca ni protege el espacio de direcciones de las pruebas unitarias. En el desarrollo temprano. Ver el Página principal de CUnit.

CuTest

Un marco simple con solo un archivo .c y uno .h que coloca en su árbol fuente. Ver el Página principal de CuTest.

CppUnit

El marco de prueba de unidad principal para C ++; también puedes usarlo para probar el código C. Es estable, desarrollado activamente y tiene una interfaz GUI. Las razones principales para no usar CppUnit para C son primero que es bastante grande, y segundo debes escribir tus pruebas en C ++, lo que significa que necesitas un compilador de C ++. Si esto no parece una preocupación, definitivamente vale la pena considerarlo, junto con otros marcos de prueba de unidades C ++. Ver el Página de inicio de CppUnit.

embUnit

embUnit (unidad integrada) es otro marco de prueba unitario para sistemas integrados. Este parece ser reemplazado por AceUnit. Página de inicio de la unidad incorporada.

MinUnit

Un conjunto mínimo de macros y eso es todo! El punto es mostrar cuán fácil es probar tu código en una unidad. Ver el Página principal de MinUnit.

CUnit para el Sr. Ando

Una implementación de CUnit que es bastante nueva, y aparentemente todavía en desarrollo temprano. Ver el CUnit para la página del Sr. Ando.

Esta lista fue actualizada por última vez en marzo de 2008.

Otros:

CMocka

CMocka es un marco de prueba para C con soporte para objetos simulados. Es fácil de usar y configurar CMocka página oficial

Criterio

Criterion es un marco de pruebas de unidades C multiplataforma que admite el registro automático de pruebas, pruebas parametrizadas y teorías, y que puede enviar a múltiples formatos, incluidos TAP y JUnit XML. Cada prueba se ejecuta en su propio proceso, por lo que las señales y bloqueos se pueden informar o probar si es necesario. Ver el Página de inicio de Criterion para más información.

HWUT

HWUT es una herramienta general de Pruebas de Unidad con gran soporte para C. Puede ayudar a crear Makefiles, generar casos de prueba masivos codificados en "tablas de iteración" mínimas, caminar a lo largo de máquinas de estado, generar C-stubs y más. El enfoque general es bastante único: los veredictos se basan en 'good stdout / bad stdout'. La función de comparación, sin embargo, es flexible. Por lo tanto, cualquier tipo de script se puede usar para verificar. Se puede aplicar a cualquier idioma que pueda producir salida estándar. Ver HWUT página principal.

Wikipedia ofrece una lista detallada de los marcos de prueba de la unidad C bajo Lista de marcos de prueba de unidades: C


418



Personalmente me gusta Marco de prueba de Google.

La verdadera dificultad para probar el código C es romper las dependencias de los módulos externos para que pueda aislar el código en unidades. Esto puede ser especialmente problemático cuando intenta hacerse pruebas del código heredado. En este caso, a menudo me encuentro utilizando el enlazador para usar funciones stubs en las pruebas.

Esto es a lo que las personas se refieren cuando hablan de "costuras"En C, tu única opción es utilizar el preprocesador o el enlazador para burlar tus dependencias.

Un conjunto de pruebas típico en uno de mis proyectos C podría verse así:

#include "myimplementationfile.c"
#include <gtest/gtest.h>

// Mock out external dependency on mylogger.o
void Logger_log(...){}

TEST(FactorialTest, Zero) {
    EXPECT_EQ(1, Factorial(0));
}

Tenga en cuenta que en realidad está incluyendo el archivo C y no el archivo de encabezado. Esto brinda la ventaja de tener acceso a todos los miembros de datos estáticos. Aquí hago una maqueta de mi logger (que podría estar en logger.o y le doy una implementación vacía. Esto significa que el archivo de prueba compila y enlaza de forma independiente del resto de la base de código y se ejecuta de forma aislada.

En cuanto a la compilación cruzada del código, para que esto funcione se necesitan buenas instalaciones en el objetivo. He hecho esto con googletest cross compiled en Linux en una arquitectura PowerPC. Esto tiene sentido porque allí tienes un shell completo y un sistema operativo para recopilar tus resultados. Para entornos menos ricos (que clasifico como cualquier cosa sin un sistema operativo completo), debería simplemente compilar y ejecutar en el host. Deberías hacer esto de todos modos para que puedas ejecutar las pruebas automáticamente como parte de la compilación.

Encuentro que probar el código C ++ es generalmente mucho más fácil debido al hecho de que el código OO en general está mucho menos acoplado que el de los procedimientos (por supuesto, esto depende mucho del estilo de codificación). También en C ++ puedes usar trucos como la inyección de dependencia y la anulación de método para obtener un código que, de lo contrario, se encapsula.

Michael Feathers tiene un excelente libro sobre prueba de código heredado. En un capítulo cubre técnicas para tratar con código no OO que recomiendo encarecidamente.

Editar: He escrito un entrada en el blog sobre el código de procedimiento de prueba unitaria, con fuente disponible en GitHub.

Editar: Hay un nuevo libro que sale de los programadores pragmáticos que aborda específicamente el código C de prueba unitaria que te lo recomiendo mucho.


139



Minunit es un marco de prueba unitaria increíblemente simple. Lo estoy usando para probar la unidad c código de microcontrolador para avr.


121



Actualmente estoy usando el marco de prueba de la unidad CuTest:

http://cutest.sourceforge.net/

Es ideal para sistemas integrados, ya que es muy ligero y simple. No tuve problemas para que funcione tanto en la plataforma de destino como en el escritorio. Además de escribir las pruebas unitarias, todo lo que se requiere es:

  • un archivo de encabezado incluido donde sea estás llamando a las rutinas CuTest
  • un solo archivo 'C' adicional para ser compilado / vinculado a la imagen
  • un código simple agregado a main para configurar y llamar a las pruebas unitarias - I solo tienes esto en un main especial () función que se compila si UNITTEST se define durante el construir.

El sistema necesita soportar un montón y algunas funcionalidades stdio (que no todos los sistemas incorporados tienen). Pero el código es lo suficientemente simple como para que puedas trabajar en alternativas a esos requisitos si tu plataforma no los tiene.

Con un uso juicioso de los bloques "C" {} externos, también es compatible con la prueba de C ++.


39



Digo casi lo mismo que ratkok, pero si tienes un giro incrustado en la unidad prueba entonces ...

Unidad - Marco altamente recomendado para el código C de prueba unitaria.

Los ejemplos en el libro que se menciona en este hilo TDD para C integrado se escriben usando Unity (y CppUTest).


33



También es posible que desee echar un vistazo a libtap, un marco de prueba C que genera el Test Anything Protocol (TAP) y, por lo tanto, se integra bien con una variedad de herramientas que salen para esta tecnología. Se usa principalmente en el mundo del lenguaje dinámico, pero es fácil de usar y se está volviendo muy popular.

Un ejemplo:

#include <tap.h>

int main () {
    plan(5);

    ok(3 == 3);
    is("fnord", "eek", "two different strings not that way?");
    ok(3 <= 8732, "%d <= %d", 3, 8732);
    like("fnord", "f(yes|no)r*[a-f]$");
    cmp_ok(3, ">=", 10);

    done_testing();
}

29



Existe un elegante marco de prueba unitario para C con soporte para objetos simulados llamado cmocka. Solo requiere la biblioteca C estándar, funciona en una variedad de plataformas informáticas (incluidas las integradas) y con diferentes compiladores.

También tiene soporte para diferentes formatos de salida de mensajes como Subunit, Test Anything Protocol y jUnit XML reports.

cmocka ha sido creado para trabajar también en plataformas integradas y también tiene soporte de Windows.

Una prueba simple se ve así:

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

/* A test case that does nothing and succeeds. */
static void null_test_success(void **state) {
    (void) state; /* unused */
}

int main(void) {
    const struct CMUnitTest tests[] = {
        cmocka_unit_test(null_test_success),
    };
    return cmocka_run_group_tests(tests, NULL, NULL);
}

los API está completamente documentado y varios ejemplos son parte del código fuente.

Para comenzar con cmocka, debe leer el artículo en LWN.net: Pruebas unitarias con objetos simulados en C

cmocka 1.0 fue lanzado en febrero de 2015.


24



No llegué a probar mucho una aplicación C heredada antes de comenzar a buscar una forma de simular funciones. Necesitaba burlarse mal para aislar el archivo C que quiero probar de los demás. Le di una oportunidad a Cmock y creo que lo adoptaré.

Cmock escanea los archivos de encabezado y genera funciones simuladas basadas en los prototipos que encuentra. Mocks le permitirá probar un archivo C en perfecto aislamiento. Todo lo que tendrá que hacer es vincular su archivo de prueba con simulaciones en lugar de sus archivos de objetos reales.

Otra ventaja de cmock es que validará los parámetros pasados ​​a las funciones simuladas, y le permitirá especificar qué valor de retorno deben proporcionar los simulacros. Esto es muy útil para probar diferentes flujos de ejecución en sus funciones.

Las pruebas consisten en las funciones típicas testA (), testB () en las que se crean expectativas, se llaman funciones para probar y verificar aseveraciones.

El último paso es generar un corredor para tus pruebas con unidad. Cmock está vinculado al marco de prueba de unidad. La unidad es tan fácil de aprender como cualquier otro marco de prueba de unidad.

Vale la pena intentarlo y es bastante fácil de entender:

http://sourceforge.net/apps/trac/cmock/wiki

Actualización 1

Otro marco que estoy investigando es Cmockery.

http://code.google.com/p/cmockery/

Es un marco C puro que respalda las pruebas y burlas de la unidad. No tiene dependencia de ruby ​​(a diferencia de Cmock) y tiene muy poca dependencia de libs externos.

Se requiere un poco más de trabajo manual para configurar simulaciones porque no genera código. Eso no representa mucho trabajo para un proyecto existente, ya que los prototipos no cambiarán mucho: una vez que tenga sus simulacros, no tendrá que cambiarlos por un tiempo (este es mi caso). La escritura extra proporciona un control completo de los simulacros. Si hay algo que no te gusta, simplemente cambia tu simulacro.

No es necesario un corredor de prueba especial. Solo necesita crear una matriz de pruebas y pasarla a una función run_tests. Un poco más de trabajo manual aquí también, pero definitivamente me gusta la idea de un marco autónomo autónomo.

Además contiene algunos ingeniosos trucos de C que no sabía.

En general, Cmockery necesita un poco más de comprensión de los simulacros para empezar. Los ejemplos te ayudarán a superar esto. Parece que puede hacer el trabajo con una mecánica más simple.


19



Como novato en C, encontré las diapositivas llamadas Desarrollo impulsado por prueba en C muy útil. Básicamente, usa el estándar assert() Juntos con && para entregar un mensaje, sin dependencias externas. Si alguien está acostumbrado a un marco de prueba de pila completo, probablemente esto no funcione :)


14



Ahi esta CUnit

Y Unidad integrada es un marco de prueba unitaria para Embedded C System. Su diseño fue copiado de JUnit y CUnit y más, y luego se adaptó un poco para Embedded C System. La unidad integrada no requiere bibliotecas estándar. Todos los objetos están asignados al área const.

Y Tessy automatiza las pruebas unitarias del software integrado.


12



El libro de Michael Feather "Working Effectively with Legacy Code" presenta muchas técnicas específicas para pruebas unitarias durante el desarrollo de C.

Existen técnicas relacionadas con la inyección de dependencia que son específicas de C y que no he visto en ningún otro lado.


11