5

Vorrei vedere un esempio per impedire a JaCoCo di segnalare i costruttori vuoti come codice non coperto in una classe Java.JaCoCo e copertura mancante del costruttore privato predefinito

Nella configurazione di Maven plug Ho

<rule> 
    <element>CLASS</element> 
     <excludes> 
     <exclude>JAVAC.SYNTHCLASS</exclude> 
     <exclude>JAVAC.SYNTHMETH</exclude> 
     </excludes> 
    </element> 
    </rule> 

Non c'è qualcosa di simile per il costruttore?

risposta

8

Questo non è supportato. Il official documentation dice:

Filtri per il codice in cui test di esecuzione è discutibile o impossibile da Design

  • privati, vuoti costruttori predefiniti - assumendo nessuna chiamata ad esso
  • getter Plain e setter
  • Blocchi che lanciano AssertionErrors - L'intero blocco deve essere ignorato se una condizione (se l'asserzione lancia un nuovo AssertionError)

vedi anche: https://github.com/jacoco/jacoco/issues/298

Aggiornamento: Questo è stato risolto in https://github.com/jacoco/jacoco/pull/529 e dovrebbe essere in 0.8.0.

1

Non è possibile disattivare questa opzione. Se hai un disperato bisogno di incontrare un cancello di qualità relativo alla copertura, puoi sempre usare una soluzione alternativa e invocare questi costruttori privati ​​attraverso la riflessione.

-1

Questo non risolve il problema essenziale che svuota i costruttori privati ​​non dovrebbero richiedere la copertura, ma per rendere effettivamente JaCoCo segnala la copertura su un costruttore privato vuoto che è necessario chiamarlo. Come si fa a farlo? Si chiama nel blocco di inizializzazione statico.

public class MyClass { 
    static { 
     new MyClass(); 
    } 
    private MyClass(){} 
} 

EDIT: scoperto che non v'è alcuna garanzia sul blocco di inizializzazione statico da eseguire. Pertanto ci si limita ad utilizzare metodi come questa:

static <T> void callPrivateConstructorIfPresent(Class<T> clazz){ 
     try{ 
      Constructor<T> noArgsConstructor = clazz.getDeclaredConstructor(); 
      if(!noArgsConstructor.isAccessible()){ 
       noArgsConstructor.setAccessible(true); 
       try { 
        noArgsConstructor.newInstance(); 
       } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
       { 
        e.printStackTrace(); 
       } 
       noArgsConstructor.setAccessible(false); 
      } 
     } catch(NoSuchMethodException e){} 
    } 
0

In questo caso l'uso, la riflessione è perfettamente accettabile, ci sono pochi e ben conosciuti classi. Il codice qui sotto potrebbe essere utilizzato con un rilevamento automatico della classe basato sul nome. Per esempio, classi ". Factory" con ulteriori affermazioni.

@Test 
public void testCoverage() 
    throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 
    coverageSingleton(MySingleton1.class); 
    coverageSingleton(MySingleton2.class); 
} 

private <S> void coverageSingleton(Class<S> singletonClass) 
    throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 
    final Constructor<S> constructor = singletonClass.getDeclaredConstructor(); 
    constructor.setAccessible(true); 
    constructor.newInstance(); 
} 
+0

In realtà non v'è una risposta più bella lì: http://stackoverflow.com/questions/4520216/how-to-add-test-coverage- a-un-costruttore privato – fabdouglas

0

Come da documentazione ufficiale, che sta per essere rilasciato con 0.8.0

Filtri per codice in cui test di esecuzione è discutibile o impossibile da design

costruttori vuoti privati ​​che non avere argomenti - Done

Potete trovare i dettagli here.

0

Dato che la versione 0.8.0 non è stata ancora rilasciata, ho creato un controllo hamcrest che controlla se una classe è una classe di utilità e inoltre chiama il costruttore privato utilizzando reflection (solo per scopi di copertura del codice).

https://github.com/piotrpolak/android-http-server/blob/master/http/src/test/java/ro/polak/http/utilities/IOUtilitiesTest.java

package ro.polak.http.utilities; 

import org.junit.Test; 


import static org.hamcrest.core.Is.is; 
import static org.junit.Assert.assertThat; 
import static ro.polak.http.ExtraMarchers.utilityClass; 

public class IOUtilitiesTest { 

    @Test 
    public void shouldNotBeInstantiable() { 
     assertThat(IOUtilities.class, is(utilityClass())); 
    } 
} 

https://github.com/piotrpolak/android-http-server/blob/master/http/src/test/java/ro/polak/http/ExtraMarchers.java

package ro.polak.http; 

import org.hamcrest.Description; 
import org.hamcrest.Matcher; 
import org.hamcrest.TypeSafeMatcher; 

import java.lang.reflect.Constructor; 
import java.lang.reflect.InvocationTargetException; 

public class ExtraMarchers { 

    private static final UtilClassMatcher utilClassMatcher = new UtilClassMatcher(); 

    public static Matcher<? super Class<?>> utilityClass() { 
     return utilClassMatcher; 
    } 

    private static class UtilClassMatcher extends TypeSafeMatcher<Class<?>> { 
     @Override 
     protected boolean matchesSafely(Class<?> clazz) { 
      boolean isUtilityClass = false; 
      try { 
       isUtilityClass = isUtilityClass(clazz); 
      } catch (ClassNotFoundException | InstantiationException e) { 
       // Swallowed 
      } 

      // This code will attempt to call empty constructor to generate code coverage 
      if (isUtilityClass) { 
       callPrivateConstructor(clazz); 
      } 

      return isUtilityClass; 
     } 

     @Override 
     protected void describeMismatchSafely(Class<?> clazz, Description mismatchDescription) { 
      if (clazz == null) { 
       super.describeMismatch(clazz, mismatchDescription); 
      } else { 
       mismatchDescription.appendText("The class " + clazz.getCanonicalName() + " is not an utility class."); 

       boolean isNonUtilityClass = true; 
       try { 
        isNonUtilityClass = !isUtilityClass(clazz); 
       } catch (ClassNotFoundException e) { 
        mismatchDescription.appendText(" The class is not found. " + e); 
       } catch (InstantiationException e) { 
        mismatchDescription.appendText(" The class can not be instantiated. " + e); 
       } 

       if (isNonUtilityClass) { 
        mismatchDescription.appendText(" The class should not be instantiable."); 
       } 
      } 
     } 

     @Override 
     public void describeTo(Description description) { 

     } 

     private void callPrivateConstructor(Class clazz) { 
      try { 
       Constructor<?> constructor = clazz.getDeclaredConstructor(); 
       constructor.setAccessible(true); 
       constructor.newInstance(); 
      } catch (NoSuchMethodException | IllegalAccessException | 
        InstantiationException | InvocationTargetException e) { 
       // Swallowed 
      } 
     } 

     private boolean isUtilityClass(Class clazz) throws ClassNotFoundException, InstantiationException { 
      boolean hasPrivateConstructor = false; 
      try { 
       clazz.newInstance(); 
      } catch (IllegalAccessException e) { 
       hasPrivateConstructor = true; 
      } 
      return hasPrivateConstructor; 
     } 
    } 
} 
Problemi correlati