2016-02-22 16 views
7

Czy istnieje sposób drukowania komunikatów Logcat (Log.i, Log.d) podczas uruchamiania testu JUnit (metoda) w Android Studio?Rejestrowanie wiadomości w teście junit z Androidem

Widzę komunikat System.out.print, ale nie ma wydruków logcat.

W konfiguracji uruchomieniowej (okno GUI w Android Studio) dostępne są opcje logcat dla testów w ramach testów Androida, ale nie dla testów JUnit.

Czy to możliwe? Dzięki za wszelkie wskazówki!

+0

Czy dowiedziałeś się, jak to zrobić? Mam teraz do czynienia z tym samym pytaniem ... –

+1

@IgorGanapolsky, możesz zobaczyć moją odpowiedź poniżej – Vasiliy

Odpowiedz

0

Szukałem tego samego i nigdy nie znalazłem prostej odpowiedzi. Wiem, że to pytanie ma ponad rok, ale nadal dobrze byłoby mieć tutaj odpowiedź na przyszłość.

Klasa android.util.Log loguje się bezpośrednio do Logcat, a implementacja dla pliku android.util.Log nie jest dostępna podczas uruchamiania testów jednostki na lokalnej maszynie JVM. Otrzymasz błąd podczas próby użycia klasy Log w testach jednostkowych, ponieważ "plik android.jar używany do uruchamiania testów jednostkowych nie zawiera żadnego rzeczywistego kodu (te interfejsy API są dostarczane tylko przez obraz systemu Android na urządzeniu) . "
See Android Documentation on Unit Testing

Więc jeśli naprawdę chcesz używać android.util.Log trzeba wyśmiewać go lokalnie i wykorzystać System.out.print drukować na konsoli. Aby rozpocząć, dodaj PowerMockito do swojego projektu. Jeśli używasz Gradle, można po prostu dodać następujące zależności:

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' 

Następny użyłem Steve'a odpowiedź here aby dowiedzieć się, jak wrócić parametr przekazany do makiety obiektu przy użyciu Mockito.

Rezultatem było coś takiego:

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"); 
    } 
} 

nadzieję, że to pomoże ktoś!

+0

Proponuję unikać PowerMocka za wszelką cenę i używać standardowych praktyk OOP, aby osiągnąć pożądane zachowanie – Vasiliy

+0

"Proponuję unikać PowerMock za wszelką cenę "- okej, może wyjaśnisz dlaczego? – user3474985

+0

Jak już powiedziałem: "używaj standardowych praktyk OOP, aby osiągnąć pożądane zachowanie". "Hackowanie" w bajtode może wydawać się prostym rozwiązaniem, ale tak nie jest, a ta ścieżka jest bardzo niechlujna. Aby uzyskać szczegółowe informacje, jak to zrobić, zobacz moją odpowiedź: – Vasiliy

3

Dane wyjściowe programu Logcat nie będą widoczne w testach jednostkowych, ponieważ funkcja Logcat ma funkcję Androida - testy JUnit mogą korzystać tylko ze standardowej wersji Java, dlatego funkcje systemu Android nie będą działać.

Co można zrobić w testach jednostkowych, to wstrzyknąć "test podwójny" w testowane komponenty. Ale połączenia Log.x są statyczne, więc nie można ich przesłonić (bez rozwiązywania np. PowerMocka, którego należy unikać za wszelką cenę).

Dlatego pierwszym krokiem będzie wprowadzenie non-statyczną klasę, która będzie zachowywać jako serwer proxy dla połączeń Log.x:

/** 
* 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); 
    } 
} 

użyć tej klasy w każdym miejscu masz Log.x połączeń teraz.

Drugi krok byłoby napisać implementację testową-double z Logger, który przekierowuje do standardowego wyjścia:

public class UnitTestLogger extends Logger{ 

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

    // similar for other methods 
} 

Ostatnim krokiem jest wstrzykiwać UnitTestLogger zamiast Logger w testach jednostkowych:

@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); 
    } 

} 

Jeśli chcesz rygorystycznie przestrzegać pojęć OOP, możesz wydobyć wspólny interfejs dla Logger i UnitTestLogger.

Powiedział, że nigdy nie spotkałem się z koniecznością zbadania połączeń Log.x w testach jednostkowych. Podejrzewam, że ty też tego nie potrzebujesz. Można uruchomić testy jednostkowe w trybie debugowania i krok nad kodem linię po linii debugger, który jest znacznie szybszy niż próbą zbadania wyjście logcat ...

Porady ogólne:

Jeśli kod testujesz zawiera statyczne połączenia Log.x, a testy jednostek nie powodują awarii - masz problem.

Zgaduję, że albo wszystkie testy są uruchamiane z Robolectric, albo masz to oświadczenie w build.gradle: unitTests.returnDefaultValues = true.

Jeśli przeprowadzisz wszystkie testy z Robolectric, to jest to po prostu nieefektywne, ale jeśli wszystkie połączenia z Androidem zwrócą wartości domyślne, pakiet testowy nie jest niezawodny. Proponuję rozwiązać ten problem, zanim przejdziesz dalej, ponieważ będzie cię gryźć w przyszłości w ten czy inny sposób.

+0

Możesz uniknąć konieczności zmiany logów w ogóle, po prostu nazywając dziennik Logger zamiast mLogger. – JulianSymes

Powiązane problemy