2017 Luglio, 10 Lunedì 16:13


Il testing è un settore dell'ingegneria del software incredibilmente importante: questo è un fatto a prescindere dal linguaggio di programmazione scelto. Mentre stavo codificando un nuovo algoritmo sotto richiesta del mio supervisor, mi sono accorto che dei test automatici per testare i cambiamenti sul mio algoritmo potevano farmi veramente comodo.

Referente Progetto: Bono Massimo

L'algoritmo era scritto in C, quindi per prima cosa mi sono messo a cercre un framework di test intuitivo e veloce da installare per poter testare il progetto. Purtroppo però non sono riuscito a trovare nulla che mi soddisfacesse completamente: alcuni framework avevano troppo codice boilerplate, ad altri mancavano delle funzionalità molto comode. Alla fine, siccome il tempo stringeva, ho usato cutest. Non ero comunque totalmente soddisfatto della scelta: prima di tutto i test hanno molto codice boilerplate. Inoltre ho scoperto dopo che la libreria ha una memory leak piuttosto noiosa (almeno per quel che riguarda l'ultima versione che ho provato). 

In passato, mentre programmavo in C++, avevo riscontrato lo stesso problema ma avevo scoperto il progetto Catch: questo fantastico progetto ha pochissimo boilerplate code per costruire i test. Inoltre le clausole macro WHEN e THEN permettono di ridurre di molto il codice di testing (aumentandone la mantenibilità).

Purtroppo Catch non support C, ma solo C++ (almeno che io sappia). Perciò ho deciso di progettare e sviluppare un nuovo framework di test. Questo nuovo framework ha come basi:

  1. Catch;
  2. JUnit;
  3. Semplciità d'uso e boilerplate code ridotto all'osso;

 Dopo un po' di sviluppo, possiamo mostrare un piccolo ma molto interessante esempio:

int main(int argc, const char* argv[]) {

	char buffer[1000];

	TESTCASE("testcase", "") {
		isprintf(buffer, "a");
		WHEN("when1", "") {
			isprintf(buffer, "b");
		}
		isprintf(buffer, "c");
		WHEN("when2", "") {
			isprintf(buffer, "d");
		}
		isprintf(buffer, "e");
		WHEN("when3", "") {
			isprintf(buffer, "f");
		}
		isprintf(buffer, "g");
	}
	assert( strcmp(buffer, "abcegacdegacefg") == 0);
	resetBuffer();
}

CrashC (il nome del nuovo framework di testing) espande il codice in 3 diversi test aventi del codice in comune:

int main(int argc, const char* argv[]) {

	char buffer[1000];

	TEST1() {
		isprintf(buffer, "a");
		isprintf(buffer, "b");
		isprintf(buffer, "c");
		isprintf(buffer, "e");
		isprintf(buffer, "g");
	}

	TEST2() {
		isprintf(buffer, "a");
		isprintf(buffer, "c");
		isprintf(buffer, "d");
		isprintf(buffer, "e");
		isprintf(buffer, "g");
	}

	TETS3() {
		isprintf(buffer, "a");
		isprintf(buffer, "c");
		isprintf(buffer, "e");
		isprintf(buffer, "f");
		isprintf(buffer, "g");
	}

	assert( strcmp(buffer, "abcegacdegacefg") == 0);
	resetBuffer();
}

Nonostante l'esempio sia semplice, è già possibile vedere come CrashC (ispirato a Catch) permette di ridurre drasticamente il codice di test ridondante. Attualmente il progetto è concretamente sviluppato da Lorenzo Nodari. Lorenzo sta anche sviluppando nuove feature di CrashC che si andranno ad aggiungere ai pregi qui elencati (come generazione di reportistica, selezione di test da eseguire e da escludere eccetera).
CrashC è ancora in piena fase di sviluppo, ma penso che entro fine estate sarà possibile rilasciare la prima versione stabile. Se si è interessati, si consiglia di controllare la repository CrashC github repo.