2016-02-22 17 views
7

C'è un modo per stampare i messaggi Logcat (Log.i, Log.d) quando si esegue un test JUnit (metodo) in Android Studio?Messaggi di registro nel test di Android Studio junit

Sono in grado di vedere il messaggio System.out.print ma non stampe logcat.

Nella finestra di configurazione (finestra GUI di Android Studio) sono disponibili le opzioni logcat per i test con test Android ma non per i test JUnit.

Questo è possibile in qualche modo? Grazie per eventuali suggerimenti!

+0

Hai scoperto come si fa? Sto affrontando la stessa domanda ora ... –

+1

@IgorGanapolsky, è possibile vedere la mia risposta sotto – Vasiliy

risposta

0

Stavo cercando la stessa cosa e non ho mai trovato una risposta diretta. So che questa domanda ha più di un anno ma, comunque, sarebbe bello avere una risposta qui per riferimento futuro.

La classe android.util.Log accede direttamente a Logcat e l'implementazione per android.util.Log non è disponibile durante l'esecuzione dei test dell'unità sulla JVM locale. Riceverai un errore quando proverai a utilizzare la classe Log nei test dell'unità perché "il file android.jar utilizzato per eseguire i test unitari non contiene alcun codice effettivo (quelle API sono fornite solo dall'immagine del sistema Android su un dispositivo) ".
See Android Documentation on Unit Testing

Quindi, se si vuole veramente utilizzare android.util.Log avrete bisogno per deridere localmente e utilizzare System.out.print per stampare sulla console. Per iniziare, aggiungi PowerMockito al tuo progetto. Se stai usando Gradle, si può semplicemente aggiungere le seguenti dipendenze:

testCompile 'junit:junit:4.12' 
testCompile 'org.powermock:powermock:1.6.5' 
testCompile 'org.powermock:powermock-module-junit4:1.6.5' 
testCompile 'org.powermock:powermock-api-mockito:1.6.5' 

Poi ho usato la risposta di Steve here di capire come restituire un parametro passato in un oggetto fittizio utilizzando Mockito.

Il risultato è stato qualcosa di simile:

import android.util.Log; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

import static org.mockito.Matchers.anyString; 
import static org.powermock.api.mockito.PowerMockito.when; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest({Log.class}) 
public class SomeUnitTest { 

    @Test 
    public void testSomething() { 
     System.out.println("Running test"); 
     PowerMockito.mockStatic(Log.class); 

     // Log warnings to the console   
     when(Log.w(anyString(), anyString())).thenAnswer(new Answer<Void>()  { 
      @Override 
      public Void answer(InvocationOnMock invocation) throws Throwable { 
       Object[] args = invocation.getArguments(); 
       if (args.length > 1) { //cause I'm paranoid 
        System.out.println("Tag:" + args[0] + " Msg: " + args[1]); 
       } 
       return null; 
      } 
     }); 
     Log.w("My Tag", "This is a warning"); 
    } 
} 

Spero che questo aiuti qualcuno!

+0

Vorrei suggerire di evitare PowerMock a tutti i costi, e utilizzare le pratiche OOP standard al fine di ottenere il comportamento desiderato – Vasiliy

+0

"Vorrei suggerire di evitare PowerMock a tutti i costi "- ok, che ne dici di spiegare perché? – user3474985

+0

Come ho detto: "usa le pratiche OOP standard per ottenere il comportamento desiderato". "Hacking" nel bytecode può sembrare una soluzione semplice, ma non lo è, e questo percorso è molto sciatto. Per i dettagli su come farlo correttamente vedere la mia risposta – Vasiliy

3

L'output di Logcat non verrà visualizzato nei test di unità perché Logcat è una funzionalità Android: i test di JUnit possono utilizzare solo Java standard, pertanto le funzionalità di Android non funzioneranno.

Ciò che è possibile fare nei test di unità è iniettare "duplicati di prova" in componenti testati. Ma le chiamate Log.x sono statiche, quindi non puoi sovrascriverle (senza risolvere ad esempio PowerMock, che dovresti evitare a tutti i costi).

Pertanto, il primo passo sarà quello di introdurre una classe non-statica che si comporterà come un proxy per Log.x chiamate:

/** 
* This class is a non-static logger 
*/ 
public class Logger { 

    public void e(String tag, String message) { 
     Log.e(tag, message); 
    } 

    public void w(String tag, String message) { 
     Log.w(tag, message); 
    } 

    public void v(String tag, String message) { 
     Log.v(tag, message); 
    } 

    public void d(String tag, String message) { 
     Log.d(tag, message); 
    } 
} 

utilizzare questa classe in ogni luogo avete Log.x chiamate ora.

Secondo passo sarebbe quello di scrivere un test implementazione-doppia Logger che reindirizza standard output:

public class UnitTestLogger extends Logger{ 

    @Override 
    public void e(String tag, String message) { 
     System.out.println("E " + tag + ": " + message); 
    } 

    // similar for other methods 
} 

L'ultimo passo è quello di iniettare UnitTestLogger anziché Logger in unit test:

@RunWith(MockitoJUnitRunner.class) 
public class SomeClassTest { 

    private Logger mLogger = new UnitTestLogger(); 

    private SomeClass SUT; 

    @Before 
    public void setup() throws Exception { 
     SUT = new SomeClass(/* other dependencies here */ mLogger); 
    } 

} 

Se si desidera essere rigorosamente rigorosi sui concetti OOP, è possibile estrarre un'interfaccia comune per Logger e UnitTestLogger.

Detto questo, non ho mai riscontrato la necessità di esaminare le chiamate Log.x nei test unitari. Sospetto che nemmeno tu ne abbia bisogno. È possibile eseguire unit test in modalità debug e scavalcare il codice di linea per linea in debugger, che è molto più veloce che tentare di indagare uscita logcat ...

Informazione generale:

Se il codice stai testando contiene le chiamate statiche Log.x ei tuoi test di unità non si bloccano - hai un problema.

Suppongo che tutti i test vengano eseguiti con Robolectric oppure questa dichiarazione è in build.gradle: unitTests.returnDefaultValues = true.

Se si eseguono tutti i test con Robolectric, quindi non è efficiente, ma se tutte le chiamate Android restituiscono valori predefiniti, la suite di test non è affidabile. Ti suggerisco di risolvere questo problema prima di procedere ulteriormente perché ti morderà in futuro in un modo o nell'altro.

+0

È possibile evitare la necessità di modificare le chiamate di registro, semplicemente nominando il log dell'istanza di Logger, invece di mLogger. – JulianSymes

Problemi correlati