JavaSvet - otvorena java zajednica

 
glavna stranica arr2javasvet  english version arr2java.net

EMMA code coverage

Igor Spasić
14 Okt 2004

EMMA je alat kojim se meri tkzv. pokrivenost koda aplikacija (code coverage). Pokrivenost koda je parametar (postotak) koji pokazuje koliki je deo aplikacije koji se zaista izvršava. Programi koji mere pokrivenost koda obično mogu i da prikažu ili označe taj konkretni deo aplikacije. Ovakva analiza se obično odvija na nivou linija izvornog koda (ako je isti dostupan), gde se prati koje linije koda su bile izvršene, a koje ne. Na osnovu ovih podataka se dobijaju i parametri pokrivenosti na nivou blokova, metoda i samih klasa.

Mera pokrivenosti koda je neprocenjiva za detektovanje tkzv. mrtvog koda - delovi programa koji se nikada ne izvršavaju. Pokrivenost koda je dragocena i za proveru i praćenje delova aplikacije koji su zaista bili izvršeni u toku korišćenja programa ili u toku rada testa. Često se zajedno sa testnim rezultatima daje i izveštaj o meri pokrivenosti koda, čime se dobija uvid šta je konkretno testirano i u kojoj meri.

Danas postoji više alata kojima se meri pokrivenost koda. Najpoznatiji takav alat je Clover koji, međutim, nije besplatan za korišćenje, niti je open-source. Što se tiče besplatnih i/ili open-source projekata, njih postoji nekoliko. Odličan pregled i poređenje trenutno dostupnih alata za merenje pokrivenosti koda se može naći ovde. Na osnovnu ovog i sličnih uporednih poređenja, komentara korisnika, kao i na osnovu procenta aktivnosti projekta na SourceForge-u, može se zaključiti da je EMMA jedan od boljih alata za merenje pokrivenosti koda, ako ne i najbolji open-source alat.

EMMA je besplatan i open-source projekat, objavljen pod "Common Public License" licencom. Nalazi se na adresi: http://emma.sourceforge.net, a poslednja verzija u vreme pisanja ovog članka je 2.0.4217.

Pregled programa EMMA

Iako se EMMA može koristiti iz komande linije, ovaj članak se bavi njenim korišćenjem iz Ant-a. U oba ova slučaja korišćenja (komandna linija i Ant) postoje 2 moda kako EMMA sakuplja podatke:


Iako on-thefly mod zvuči zgodno za upotrebu, offline mod je sveobuhvatniji jer se može primeniti na sve tipove aplikacija (uključujući i EJB), što nije slučaj sa on-the-fly modom. Zato se ovaj članak bavi samo offline modom i njegovom upotrebom iz Ant-a.

Offline mod

Kao što je već rečeno, offline proces merenja je podeljen u 3 koraka:

  1. Instrumentacija (instrumentation) - predstavlja inicijalnu pripremu klasa koje se analiziraju. Ova priprema se odvija na nivou bajtkoda svih klasa koje korisnik specificira. U ovom koraku se generiše i metadata fajl ovih klasa koji služi za kasnije povezivanje podataka o pokrivenosti koda sa originalnim klasama.

  2. Izvršavanje (execution) - samo izvršavanje programa. Za razliku od uobičajenog načina izvršavanja, koriste se klase pripremljene u prethodnom koraku instrumentacije, a ne originalne klase programa.

  3. Generisanje izveštaja (report) - na osnovu metadata fajla klasa i podataka sakupljenih tokom izvršavanja programa, generiše se izveštaj u nekom pogodnom obliku.

Ceo proces je, dakle, jednostavan: treba izabrati klase nad kojima se radi analiza pokrivenosti koda, izvršti aplikaciju i na kraju generisati izveštaj.

Primer

Za primer je uzeta jednostavna aplikacija čije izvršavanje zavisi od pseudo-slučajnih brojeva, tako da je procenat aplikacije koji učestvuje u jednom izvršavanju slučajan. Sledi analiza dela Ant build fajla koji definiše task "emma" kojim se radi merenje pokrivenosti koda ovog jednostavnog primera.

Priprema

Pre definicije samog taska potrebno je izvršiti standardnu pripremu:

<path id="emma.lib" >
<pathelement location="${dir.lib}/emma.jar"/>
<pathelement location="${dir.lib}/emma_ant.jar"/>
</path>
<taskdef resource="emma_ant.properties" classpathref="emma.lib"/>
<property name="emma.dir.instr" value="emma.instr"/>
<property name="emma.dir.out" value="emma"/>

Ovde nema ničeg nepoznatog: lociraju se EMMA jar-ovi, definiše se EMMA task, kao i imena 2 foldera koja će se koristiti za instrumentovane klase i za kreiranje izveštaja.

1. Instrumentacija

<target name="emma" description="runs EMMA code coverage">
<emma>
<instr destdir="${emma.dir.instr}" metadatafile="${emma.dir.out}/metadata.emma" merge="true">
<instrpath>
<pathelement location="${dir.class}"/>
</instrpath>
</instr>
</emma>

Za instrumentaciju je potrebno naznačiti koje klase se analiziraju i koje je ime metada fajla koji će biti generisan. Važno je napomenuti da treba pažljivo odabrati i selektovati klase za instrumentaciju, kako bi se merenje ticalo samo odabranih klasa. Izbor klasa se radi u instrpath tasku (ili u istoimenom atributu instr taska). Instrumentacija priprema odabrane klase i takve kopira u prethodno definisan folder za instrumentovane klase (${emma.dir.instr}). Pri tom se generiše metadata fajl (metadata.emma).

2. Izvršavanje

	<java classname="RunMe" fork="true">
<classpath>
<pathelement location="${emma.dir.instr}"/>
<path refid="classpath"/>
<path refid="emma.lib"/>
</classpath>
<jvmarg value="-Demma.coverage.out.file=${emma.dir.out}/coverage.emma" />
<jvmarg value="-Demma.coverage.out.merge=false" />
</java>

Izvršavanje programa zahteva par napomena. Pre svega, obavezno je navesti folder u kome su instrumentovane klase (${emma.dir.instr}) kao prvi u CLASSPATH-u. Time se obezbeđuje da se prilikom izvršavanja programa koriste instrumentovane klase, a ne originalne. Zatim sledi standardni programski CLASSPATH kome se dodaju EMMA jar-ovi. Slede dva argumenta koji definišu ime fajla u koji će se upisivati podaci o pokrivenosti tokom izvršavanja programa (coverage.emma).

3. Generisanje izveštaja

	<emma>
<report sourcepath="${dir.src}">
<fileset dir="${emma.dir.out}">
<include name="*.emma"/>
</fileset>
<txt outfile="${emma.dir.out}/coverage.txt"/>
<html outfile="${emma.dir.out}/coverage.html"/>
</report>
</emma>
<delete dir="${emma.dir.instr}"/>
</target>

Na kraju, kada se program završi, ostaje da se pokupe metadata i generisani podaci, analiziraju i da se generiše izveštaj. Ovde treba uočiti atribut sourcepath taska report kojim se definiše putanja do sorsa klasa koje su analizirane (tj. koje su bile instrumentovane u prvom koraku). Iako nije obavezno imati sors instrumentovanih klasa, njegovo uključivanje u izveštaj daje značajno pregledniji izveštaj i analizu koja ide do nivoa linije koda. Što se tiče izveštaja postoji nekoliko izlaznih formata, od kojih je HTML možda najinteresantniji. Generisanje izveštaja je prilično konfigurabilno te ih je lako moguće prilagoditi prema potrebama korisnika.

Na kraju se briše folder u kome su skupljane instrumentacione klase. Ovo nije neophodno, čak ni poželjno, jer jednom instrumentovane klase neće ponovo biti pripremane. Ovde se, ipak, taj folder briše isključivo iz pokaznih razloga.

Rezultati

Kada se pokrene primer, jedan mogući izveštaj je i sledeći:

emma:
    [instr] processing instrumentation path ...
    [instr] instrumentation path processed in 203 ms
    [instr] [1 class(es) instrumented, 0 resource(s) copied]
    [instr] metadata merged into [C:\Download\_emma\emma\emma\metadata.emma] {in 16 ms}
     [java] EMMA: collecting runtime coverage data ...
     [java] foo2
     [java] foo1
     [java] EMMA: runtime coverage data written to [C:\Download\_emma\emma\emma\coverage.emma] {in 15 ms}


   [report] processing input files ...
   [report] 2 file(s) read and merged in 31 ms
   [report] writing [txt] report to [C:\Download\_emma\emma\emma\coverage.txt] ...
   [report] writing [html] report to [C:\Download\_emma\emma\emma\coverage.html] ...
   [delete] Deleting directory C:\Download\_emma\emma\emma.instr

Jasno se uočavaju sva 3 koraka offline moda. U ovom slučaju se vidi da su od 3 foo metoda izvršena samo 2 (foo1() i foo2()). Metod foo3() je jedini metod koji uopšte nije izvršen.

Pregled izveštaja

Glavni, sumarni, izveštaj i izveštaj po paketima:



Izveštaj po jednom paketu i njegovim klasama:



I, konačno, najinteresantniji izveštaj po jednoj klasi, njenim metodama sve do nivoa linije:



Download

Opisan primer se može downloadovati (8 KB). VAŽNO: primer namerno ne sadrži EMMA jar-ove, da bi download bio manji!!! Da bi primer bio kompletan potrebno je kopirati biblioteke emma.jar i emma_ant.jar iz distribucione arhive EMMA projekta u lib folder primera.