Enri Blog

7 Settembre, 2006

TDD con PL/SQL: utPLSQL

Archiviato in: Diario di bordo, Test Driven Development (TDD) — Enri @ 9:32 am

Negli ultimi giorni ho rispolverato le mie conoscenze di PL/SQL, per scrivere dei banali web-service LOW REST invocati da un Interactive Voice Responder, che sfruttano alcune succose funzionalità offerte da Oracle DBMS 10g. Sono tra quelli che credono che 9 volte su 10 non sia cosa buona e giusta scrivere della logica di business nel database, ma in questa situazione ho i miei buoni motivi per farlo (e magari ve ne parlo in un altro post).

Ma veniamo all’argomento del post. Come potete vedere dal logo qui a destra, sono test driven, e quando vi prende il virus, non guarite più :) . Ho quindi deciso di programmare a la TDD anche in PL/SQL, anche per la ruggine che si è posata sulla mia memoria.


Le classi (ops volevo dire i package) che implementano xUnit in PL/SQL si possono trovare qui e la libreria si chiama utPLSQL. Installarlo è semplicissimo:

  1. unzip del contenuto del download in una directory
  2. dalla directory code dove avete fatto l’unzip lanciate sqlplus sullo schema sul quale volete installare utPLSQL
  3. da sqlplus: @ut_i_do_install

utplsql non pone alcun vincolo sullo schema sul quale installarlo, l’importante è che l’utente che poi eseguirà i test abbia le grant necessarie a vederlo. E’ invece buona norma (ma non richiesto) che i test case siano nello stesso schema delle procedure da testare.

Questo è quanto! Come potete vedere, lo script ha creato una serie di package, tutti con prefisso ut.

A questo punto scrivere i nostri test di unità è molto semplice. Supponiamo di voler testare la procedure get_id_addetto_by_cell.



CREATE OR REPLACE PACKAGE test_get_id_addetto_by_cell
	IS
	PROCEDURE ut_setup;
	PROCEDURE ut_teardown;

PROCEDURE ut_get_id_addetto_by_cell;
END test_get_id_addetto_by_cell;
/

Le due procedure ut_setup e ut_teardown sono i nostri setUp e tearDown. La procedure di test deve avere nome con prefisso ut per poter essere riconosciuta come test case.



CREATE OR REPLACE PACKAGE BODY test_get_id_addetto_by_cell IS
	 PROCEDURE ut_setup IS
	 BEGIN
	  INSERT INTO R33_AN_ADDETTI (CID, COGNOME, CELLULARE)
                 VALUES ('E-TEST', 'TDD, '123456');
	 END ut_setup;

	 PROCEDURE ut_teardown IS
	 BEGIN
		ROLLBACK;
	 END ut_teardown;

	 PROCEDURE ut_get_id_addetto_by_cell IS
	 BEGIN
		utAssert.eq (
		   'E-TEST',
		    mobi_query.get_id_addetto_by_cell('123456'),
		   'E-TEST'
		);
	 END ut_get_id_addetto_by_cell;

END test_get_id_addetto_by_cell;
/

A questo punto per lanciare il test (da TOAD o da sqlplus):

  • exec utplsql.run(‘test_get_id_addetto_by_cell’)


>    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
  >   S    S  U     U  C   C   C   C  E        S    S   S    S
  >  S        U     U C     C C     C E       S        S
  >   S       U     U C       C       E        S        S
  >    SSSS   U     U C       C       EEEE      SSSS     SSSS
  >        S  U     U C       C       E             S        S
  >         S U     U C     C C     C E              S        S
  >   S    S   U   U   C   C   C   C  E        S    S   S    S
  >    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
  .
   SUCCESS: "test_get_id_formazione_by_cell"
  .
  > Individual Test Case Results:
  >
  SUCCESS - ut_get_id_addetto_by_cell.TEST_RITORNA_CELL: EQ "E-TEST" Expected "E-TEST" and got "E-TEST"

E’ anche possibile creare test suite.

Questo è quanto. Esiste anche un front end grafico per utPLSQL, OUnit, ma non ho avuto modo di provarlo.

TDD rulez! :)

6 Commenti »

  1. Una sola cosa suona strana: le procedure ut_setup ed ut_teardown vengono eseguite solo una volta per package di test: al contrario del comportamento di xUnit non racchiudono ogni procedure del package (cioè ogni test case).

    In effetti questo può portare ad un’esplosione di package (uno per fixture) da gestire opportunamente…

    Commento di Enri — 12 Settembre, 2006 @ 10:39 am

  2. Altra particolarità: se scriviamo più di una assert nel nostro test case, la libreria non si ferma alla prima assert che fallisce, ma procede a valutarle tutte, e a dare nel report del test l’esito di ognuna.

    Commento di Enri — 12 Settembre, 2006 @ 12:21 pm

  3. [...] La parte più onerosa sarebbe quella di implementare un piccolo motore che permetta di aggiugere dinamicamente i criteri di ricerca espressi dall’utente nella form. Tuttavia il costrutto ‘EXECUTE IMMEDIATE’ del PL/SQL ci verrebbe in aiuto dando vita di fatto ad un linguaggio di scripting interpretato a runtime (alternativamente ad una soluzione fatta in casa si veda PL/XML). Potremmo poi controllare la complessità accidentale del mondo procedurale programmando alla TDD con utPLSQL. E’ interessante notare come un approccio di questo tipo non impugni la spada degli oggetti per combattere contro il mondo relazionale ma al contrario sfrutta tutte le funzionalità offerte da un RDMBS per cercare una soluzione semplice e mirata al problema. Nella soluzione a cui sto pensando, la BL non è sparsa un po’ sul DB ed un po’ implementata in Java: il PL/SQL con SQLXML ci fornirebbe solo la funzionalità di esporre (quindi in lettura) le nostre tabelle in XML nativamente, così da poter alimentare direttamente la parte di Presentation. Spingendoci un po’ oltre potremmo esporre tali piccoli servizi come webservices (LOW) REST, invocabili direttamente via AJAX, eliminando ogni bisogno di avere un Model “cargo” in Java. [...]

    Pingback di ORM con MVC: un fallimento? « Enri Blog — 17 Settembre, 2006 @ 3:22 pm

  4. [...] Quali test effettuare al passo 4.? Anche qui dobbiamo creare dei test di regressione a piccoli ed in modo incrementale, testando sia il “database code” (ad esempio stored procedure, funzioni, trigger, etc), sia gli aspetti più di interfaccia (ad esempio l’esistenza di tabelle, procedure, le definizioni di viste, etc). Stiamo quindi facendo un forte salto in avanti rispetto al solo testing del codice agganciato al db con strumenti quali utPLSQL. [...]

    Pingback di Database legacy? Un ricordo del passato con TDDD « Enri Blog — 4 Ottobre, 2006 @ 12:11 pm

  5. > la libreria non si ferma alla >prima assert che fallisce,

    Se vuoi farlo basta chiamare la utAssert.eq specificando TRUE nel parametro raise_exc_in.

    Complimenti per il blog. Ho sparso “pomodori” per la mia azienda :-)

    Commento di Massimo — 17 Novembre, 2006 @ 6:40 pm

  6. Ciao Massimo, grazie per la info e per i complimenti.

    Volevo informarti che il blog ha cambiato casa: mi farebbe piacere se mi seguissi su

    http://redgreenrefactor.it

    Grazie e a presto!

    Commento di Enri — 17 Novembre, 2006 @ 8:09 pm


RSS feed dei commenti a questo articolo. TrackBack URI

Lascia un commento

Blog su WordPress.com.