Testeando una función con paso de tipos struct entre mocks, test y código bajo test.

34 views
Skip to first unread message

Geni Suarez

unread,
Dec 21, 2016, 5:52:41 AM12/21/16
to Embebidos32

Estoy empezando a experimentar con el testing unitario, trabajo con Cpputest para un proyecto de C embebido en un ST. Quizás tenga dudas de principiante, pero las tengo y quisiera poder aclararlas si alguien identifica rápidamente una respuesta o consejo. 

Digamos que tengo montado un test para una función RFID_DRV_GetStatus() que va a devolver una struct. Una struct de tipo RFIDDrvStatus. Pero los campos de esta struct serán actualizados una vez recibe otra estructura (de la que va a tomar algunos campos) procedente de una llamada de sistema -a la que voy a mockear y fingir un retorno (aún no está implementado ese paso pero lo haré). En este punto no importa el tipo de dato para la pregunta que voy a formular. Sólo tened en cuenta que no va a ser del mismo tipo declarado que status_val. Eso seguro.   

TEST(RFID_Drv,RFID_DRV_GetStatus_test )
{
RFIDDrvStatus status_val = {0};
RFIDDrvStatus status_val_check;
       /*struct nueva con valores para hacer yo luego unas comparaciones*/
status_val_check.AUTOCALIB_FLAG=TRUE;
status_val_check.WAKE_FLAG=TRUE;
status_val_check.DATA_READ_FLAG=TRUE;
status_val_check.ID_READ_FLAG=FALSE;
status_val_check.STOP_FRAME_FLAG=FALSE;
status_val_check.DATA_ERROR = NONE;
uint32_t TEST_DATA_ROW_VALUE=15;
mock().enable();

mock().expectOneCall("HAL_AS393x_GetStatus"); //esta llamada le devolverá unos datos (en forma de estructura y diferente a la del retorno de la función a testear: se aprecia en código de la función a testear)
mock().expectOneCall("HAL_AS393x_GetData").andReturnValue(TEST_DATA_ROW_VALUE);
status_val = RFID_DRV_GetStatus(); //se puede???
CHECK_EQUAL(status_val,status_val_check);//revisar nomenclatura al comparar structs
mock().disable();
}

Mi pregunta es, de las dos líneas que están en negrita, teniendo en cuenta que los mocks anteriores, que devuelven valores para que RFID_DRV_GetStatus() se monte la estructura que comento y la devuelve como valor de retorno a status_val; es correcto? puede hacerse sin que presente conflictos? 

Nota: la estructura  status_val no tiene por qué ser del mismo tipo que el mock le pasará. La llamada mockeada le pasará unos datos de otro tipo y dentro de la función a testear ya se encargá su lógica de construir status_val.

Por si os ayuda tener el código de la función de la que hacemos test de grupo ahí la dejo (aunque sólo inicializa una estructura): 

//y la definición de structs
typedef enum
{
NONE = 0x00,
BITS_READ_ERROR = 0X01,
MANCHESTER_ERROR = 0X02,
START_BIT_ERROR  = 0X03,
STOP_BIT_ERROR = 0X04,
NEGATED_DATA_ERROR = 0X05,
CRC_ERROR = 0X06
}RFID_DataError;

typedef struct
{
bool_t AUTOCALIB_FLAG;
bool_t WAKE_FLAG;
bool_t DATA_READ_FLAG;
bool_t ID_READ_FLAG;
bool_t STOP_FRAME_FLAG;
RFID_DataError DATA_ERROR;
}RFIDDrvStatus;

typedef struct
{   
    bool_t                  WAKE_FLAG;
    bool_t                  DATA_READ_FLAG; 
}HAL_AS393X_Status;

RFIDDrvStatus RFID_DRV_GetStatus(void)
{

        HAL_AS393X_Status HAL_Status;
/* Gets HAL_AS393X Status */
HAL_Status=HAL_AS393x_GetStatus();
/* Updates RFID Driver Status */
RFIDStatus.AUTOCALIB_FLAG=RFIDStatus.AUTOCALIB_FLAG;
RFIDStatus.WAKE_FLAG=HAL_Status.WAKE_FLAG;
RFIDStatus.DATA_READ_FLAG=HAL_Status.DATA_READ_FLAG;
RFIDStatus.ID_READ_FLAG=RFIDStatus.ID_READ_FLAG;
RFIDStatus.STOP_FRAME_FLAG=RFIDStatus.STOP_FRAME_FLAG;
RFIDStatus.DATA_ERROR=RFIDStatus.DATA_ERROR;

        return RFIDStatus;
}

Espero haberme hecho entender y agradezco la atención de antemano. 
Un cordial saludo, chicos. 

martin ribelotta

unread,
Dec 21, 2016, 7:24:48 AM12/21/16
to embebidos32@
Es correcto, la asignación de una struct en C/C++ se transforma en un
memcpy internamente.

Por supuesto, es poco eficiente, pero es totalmente legal hacer:

extern struct mystruct myfunc(...);
struct mystruct s1;
struct mystruct s2;
s1.a =...
s1.b =...
....
s2 = myfunc(...params...);
compare(s1, s2);
...

Lo que si, yo no confiaria en que:
struct mystruct s1 = {0};
Funcione, porque eso pondria el primer elemento de la estructura a
cero (distinto es con los array que todos sus elementos tienen el
mismo nombre)
Para eso, en C al menos, solo se puede hacer:
memset(&s1, 0, sizeof(s1));
> --
> -- Recibiste este mensaje porque estás suscripto al Grupo Google
> Embebidos32. Para postear en este grupo, escribe un email a
> embeb...@googlegroups.com. Para des-suscribirte, envía un email a
> embebidos32...@googlegroups.com. Para más opciones, visita el sitio
> del grupo en https://groups.google.com/d/forum/embebidos32?hl=es
> ---
> Has recibido este mensaje porque estás suscrito al grupo "Embebidos32" de
> Grupos de Google.
> Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes,
> envía un correo electrónico a embebidos32...@googlegroups.com.
> Para acceder a más opciones, visita https://groups.google.com/d/optout.

Geni Suarez

unread,
Dec 21, 2016, 7:40:17 AM12/21/16
to Embebidos32
Buenas, Ruso, 
supongo que status_val = RFID_DRV_GetStatus(); machacaría los campos con los que devolvería ella misma. De todos modos si con esa instrucción salvo posibles conflictos lo utilizaré para inicializar las structs como norma de buena praxis. 

Muchas gracias por la aclaración. Buen aporte. 

Espero no abusar si lanzo otra pregunta relacionada con el paso de struct en un test. Abriré un nuevo hilo para que otros miembros con dudas similares puedan identificarse rápido. 

Leandro Francucci

unread,
Dec 21, 2016, 8:11:15 AM12/21/16
to embeb...@googlegroups.com
Hola Geni,
También podrías probar con otro prototipo para la función RFID_DRV_GetStatus(), en principio más eficiente que la anterior, por ejemplo:

RFIDDrvStatus *RFID_DRV_GetStatus(void);
int RFID_DRV_GetStatus(RFIDDrvStatus *drvStatus);

Obviamente, cada caso requiere una implementación diferente con sus ventajas y desventajas ;)
Saludos!

LF

--
-- Recibiste este mensaje porque estás suscripto al Grupo Google Embebidos32. Para postear en este grupo, escribe un email a embeb...@googlegroups.com. Para des-suscribirte, envía un email a embebidos32+unsubscribe@googlegroups.com. Para más opciones, visita el sitio del grupo en https://groups.google.com/d/forum/embebidos32?hl=es

---
Has recibido este mensaje porque estás suscrito al grupo "Embebidos32" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a embebidos32+unsubscribe@googlegroups.com.

Geni Suarez

unread,
Dec 21, 2016, 8:29:55 AM12/21/16
to Embebidos32
Buenas Leandro, en principio me irían bien con propuestas con el menor nº de punteros ya que tengo previsto trabajar bajo el standar MISRA que únicamente permite el uso de punteros como paso por parámetros y por otro lado todo lo que implique por mi parte modificar las fuentes de producción mejor evitarlo. Puntero a una función no estoy segura que el estándar MISRA lo permita. No obstante lo tengo presente. Puede que sí quede dentro del marco (sólo que ahora mismo, todavía no lo he estudiado en profundidad). 


Y muchas gracias por ilustrarme, porque aunque no lo pudiera aplicar en este proyecto, como concepto me es útil conocer alternativas. 

Leandro Francucci

unread,
Dec 21, 2016, 8:59:12 AM12/21/16
to embeb...@googlegroups.com
Bien, sólo para no confundir a la comunidad, ninguno de los dos prototipos alternativos utilizan puntero a función. Por otro lado, en caso que pudieras modificar el código de producción o para otra implementación, podrías utilizar la segunda alternativa, la cual devuelve un entero y un puntero a través de un parámetro.

Saludos!

LF

--
-- Recibiste este mensaje porque estás suscripto al Grupo Google Embebidos32. Para postear en este grupo, escribe un email a embeb...@googlegroups.com. Para des-suscribirte, envía un email a embebidos32+unsubscribe@googlegroups.com. Para más opciones, visita el sitio del grupo en https://groups.google.com/d/forum/embebidos32?hl=es

---
Has recibido este mensaje porque estás suscrito al grupo "Embebidos32" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a embebidos32+unsubscribe@googlegroups.com.

Geni Suarez

unread,
Dec 21, 2016, 9:23:17 AM12/21/16
to Embebidos32
Perdona mi inexactitud, pensaba que con RFIDDrvStatus *RFID_DRV_GetStatus(void); apuntábamos a la función. Todavía en mi nivel no he utilizado esta sintaxis y no controlo tanto a lo que realmente puede estar apuntando. Así que dado que estaba equivocada serías tan amable de corregirme sobre lo que estamos diciendo en esta instrucción? Creo un puntero que apunta a un dato tipo struct pero no sé cómo explicar qué sucede cuando escribimos al lado una función en lugar del nombre de una variable. Es importante para aprender y mejorar el clarificar estas lagunas :).

Perdona las molestias. 

Leandro Francucci

unread,
Dec 21, 2016, 9:44:24 AM12/21/16
to embeb...@googlegroups.com
El prototipo RFIDDrvStatus *RFID_DRV_GetStatus(void) indica que RFID_DRV_GetStatus es una función que no posee argumentos y devuelve un puntero del tipo RFIDDrvStatus.

Cuando puedas te recomiendo fervorosamente leer (y ensayar los ejercicios) del capítulo 5 "Punteros y arreglos" del libro "El lenguaje de programación C" de Kernighan & Ritchie, que además es "el" manual de referencia de C. Adicionalmente, ya que ciertas declaraciones de C son complejas o no tan fáciles de interpretar de un sólo vistazo, te recomiendo estudiar el artículo Reading C type declarations, el cual incluye la precedencia de operadores.

Saludos!

LF

--
-- Recibiste este mensaje porque estás suscripto al Grupo Google Embebidos32. Para postear en este grupo, escribe un email a embeb...@googlegroups.com. Para des-suscribirte, envía un email a embebidos32+unsubscribe@googlegroups.com. Para más opciones, visita el sitio del grupo en https://groups.google.com/d/forum/embebidos32?hl=es

---
Has recibido este mensaje porque estás suscrito al grupo "Embebidos32" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a embebidos32+unsubscribe@googlegroups.com.

Geni Suarez

unread,
Dec 21, 2016, 9:59:36 AM12/21/16
to Embebidos32
Oh muchas gracias por el aporte. 
Tomo nota. 
Reply all
Reply to author
Forward
0 new messages