lunedì 6 maggio 2013

UnitTest per PMD 4.2.6

Una volta creata una nuova rule in PMD occorre preparare i relativi UnitTests.
In PMD 4.2.6 ad ogni ruleset corrisponde un package per gli unitTest.
Il package è composto da fiale .java e file .xml.
Ogni file .xml contiene un set di test standard, cioè contiene una serie di <test-code> così strutturati:

  • <description>: contiene una descrizione che verrà visualizzata nel report JUnit in caso di errore
  • <rule-property>: ogni elemento di questo tipo descrive una property della rule in esame
  • <expected-problems>: numero atteso di errori ottenuti dall'esecuzione della rule sull'attuale caso di test
  • <code>: pezzo di codice su cui applicare la rule
  • Il nome del file .xml coincide con il nome della rule da testare.
La gestione di questa tipologia di test è eseguita all'interno di SimpleAggregatorTst.java. Qui il metodo runTests() si occupa di eseguire su ogni .xml i casi di test previsti per la rule in esame.

In particolare occorre definire una classe che estende ... ed in cui si caricano tutte le regole con il metodo addRule():

public void setUp() {
        addRule("codesize", "ExcessivePublicCount");

In questo modo si crea una suite di test associata ad un ruleset, e dove gli specifici casi di test sono caricati da fogli .xml associati alle singole rule definite nel ruleset.

E' possibile però definire una suite di test associata ad una classe 

Un secondo modo per eseguire test più complessi è quello di scrivere una suite di test associata ad una singola rule, non ruleset come prima.
In questa classe si può far riferimento ad altri casi di test espressi in file .xml come visto prima, ed usarli in metodi di test con annotazione @Test nel formato JUnit.

Riassumento vediamo alcuni esempi di gestione di UnitTest:

Aggiunta di un nuovo ruleset e relativi unit tests:
Il nuovo ruleset va aggiunto nella cartella di progetto "rulesets", ad esempio: rulesets\coperBasicBE.xml

Una volta aggiunto il ruleset .xml, si deve aggiungere la relativa cartella sotto "regress" del progetto, ad esempio si aggiunge la cartella test/net/sourceforge/pmd/copergmps/vp/rules.
In questa cartella si crea la nuova classe CoperBasicBERulesTest.java
In questa classe, nella versione più semplice, si aggiunge il metodo:


public
void setUp() {
addRule("coperBasicBE", "SetRollbackOnlyMustBeOnlyInEjb"); }

   dove si passano come parametri il nome del ruleset e il nome della rule da testare.

Ricordarsi di modificare populateNameMap() in SimpleRuleSetNameMapper in package net.sourceforge.pmd; altrimenti i non si può caricare la rule con addRule.

A questo punto basta creare un nuovo documento .xml da posizionarsi nella sottocartella xml, rinominandolo con il nome della rule da testare, ad esempio

xml\SetRollbackOnlyMustBeOnlyInEjb.xml

All'interno di questo file si indicano tutti i dati per verificare la regola. Ad esempio.
<?xml version="1.0" encoding="UTF-8"?>
<test-data>
<test-code>
<description><![CDATA[
no braces
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
package it.copergmps.jq.antiriclaggio.bd;public class AnagrafeBD implements IAnagrafeBD {
public Boolean verificaSoggettoRegistrazioneAR(final Integer codiceAzienda, final Long ngrTitolare) throws AntiriclaggioBlockingException {
try {
ContestoUtil contesto = new ContestoUtil();
HAAnagrafePojoPubFactory factory = contesto.getHAFactory();
ngrConforme = factory.getVerificaAntiriciclaggioPOJOInstance("OnLine").
verificaAssoggettabilitaAnagraficaARPerNGR(codiceAzienda.intValue(), ngrTitolare.longValue());
} catch (Exception ex) {
ejbContext.setRollbackOnly();
}
return ngrConforme;
}
}
]]></code>
</test-code>
</test-data>


Aggiunta di un UT di tipo xml ad una rule esistente:

  • Si identifica il ruleset in cui si trova la rule su ci intervenire. Ad esempio per la rule CyclomaticComplexity, il ruleset di riferimento è codesize.xml
  • Noto il nome del ruleset, si ricava il nome del package di test di riferimento: test.net.sourceforge.pmd.rules.codesize
  • Da qui vediamo che i test per questa rule sono definiti sia tramite .xml che tramite classe java. In prima analisi si vuole agire solo sui test standard .xml.
  • Aprendo CyclomaticComplexity.xml andiamo ad aggiungere 
      <test-code>
        <description>
         <![CDATA[
Testing variazioni al report level, abbassandolo a 3
      ]]>
      </description>
        <rule-property name="reportLevel">3</rule-property>      
        <expected-problems>1</expected-problems>
           <code>
            <![CDATA[
public class Foo {
 public void example() {
  int x = 0;
  int a = 0;
  int b = 0;
  int c = 0;
  int d = 0;
  int a1 = 0;
  int a2 = 0;
  int b1 = 0;
  int b2 = 0;
  int z = 0;
  int h = 0;
  int e = 0;
  int f = 0;
  if (a == b) {
      if (a1 == b1) {
   x = 2;
      } else if (a2 == b2) {
   x = 2;
      } else {
   x = 2;
      }
  } else if (c == d) {
      while (c == d) {
   x = 2;
      }
  } else if (e == f) {
      for (int n = 0; n < h; n++) {
   x = 2;
      }
  } else {
      switch (z) {
      case 1:
   x = 2;
   break;
      case 2:
   x = 2;
   break;
      case 3:
   x = 2;
   break;
      default:
   x = 2;
   break;
      }
  }
 }
}
     ]]>
     </code>
       <code-ref id="basic-violation"/>
    </test-code>

                                                                                                                                      • Eseguendo gli UT, facendo attenzione che in build.xml di ant sia richiamato il target regress, dovremmo avre 0 errori.

                                                                                                                                      • Alzando la soglia a 10 e lasciando errore atteso a 1 dovremmo avere una segnalazione di errore<rule-property name="reportLevel">10</rule-property>   
                                                                                                                                      <expected-problems>1</expected-problems>

                                                                                                                                      Nessun commento: