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.
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.
Kao što je već rečeno, offline proces merenja je podeljen u 3 koraka:
Ceo proces je, dakle, jednostavan: treba izabrati klase nad kojima se radi analiza pokrivenosti koda, izvršti aplikaciju i na kraju generisati izveštaj.
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.
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.
<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).
<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).
<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.
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.
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:

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.