2016-05-16 2 views
2

stub Ich verwende Junit4 und Mockito zum Schreiben meiner Testfälle. In einer der zu testenden Klassen gibt es eine Funktion init(), die vom Konstruktor aufgerufen wird.Nicht in der Lage, post-Methode von android.os.Handler Klasse

void init(){ 
//Some code 
    Handler handler = new Handler(Looper.getMainLooper()); 
    handler.post(new Runnable() { 
     @Override 
     public void run() { 
     //Some code 
     } 
    }); 
} 

Die folgende Ausnahme ausgelöst wird, wenn constructor dieser Klasse zu schaffen versuchen.

java.lang.RuntimeException: Method post in android.os.Handler not mocked. 

Dann habe ich versucht post Methode der Handler Klasse mit dem folgenden Code

Handler handler = spy(new Handler()); 
when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 

Aber noch ich auf immer den gleichen exception halten zu verspotten. Was soll ich tun, um die Post-Methode der Handler-Klasse zu stopfen?

Antwort

0

Es ist schwer zu sagen, ohne mehr von Ihrem Kontext zu sehen, aber ich sehe zwei Möglichkeiten.

Erstens, wenn Sie die Fähigkeit haben, können Sie die Verwendung von new für etwas, das Sie benötigen, um zu spielen, vermeiden. Sie können es entweder in den Konstruktor injizieren oder eine Factory in den Konstruktor einfügen und die Factory mocksen, so dass Sie davon Handler mockten. In den meisten Fällen ist etwas in dieser Richtung der bevorzugte Ansatz. Wenn das nicht praktikabel ist, können Sie PowerMock to construct new objects verwenden.

Verwenden Sie PowerMockito.whenNew, z.

Handler handler = spy(new Handler()); 
when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 
whenNew(Handler.class).withExpectedArguments(looper).thenReturn(handler); 

Dieser Code ist nicht getestet, sollte aber grundsätzlich funktionieren.

0

Sie sind richtig bei der Interpretation von „Methode nicht spotten“: Sie sind a no-implementation version of the Android system library verwenden, so dass Sie hier spöttisch verwenden müssen, oder Sie werden wie Robolectric in eine Bibliothek wechseln müssen, die Java-Implementierungen von Klassen wie Handler zum Testen hat .

Sie benötigen doReturn für Ihren Stub. Eines der interessantesten ungewollten Aspekte der when Syntax ist, dass es das Verfahren tatsächlich nennt es Anstoßen:

when(handler.post(Matchers.any(Runnable.class))).thenReturn(true); 
// calls 
// handler.post(   null   ) 

Und weil Spione die wirkliche Methode standardmäßig aufrufen, werden Sie die problematische Methode tatsächlich aufrufen, während auf Stub versucht es. Verwenden Sie stattdessen doReturn, um Mockito anzuweisen, den Stub vorübergehend zu deaktivieren.

doReturn(true).when(handler).post(Matchers.any(Runnable.class)); 

Sie müssen den Stummel in Ihrem Test injizieren. Dies ist ein wenig schwierig, weil Sie im Konstruktor "schweres Heben" machen; Du verlierst eine Gelegenheit nach dem Bau, um deinen Handler auszutauschen. jhericks mentions a PowerMock solution, obwohl ich Refactoring empfehlen, so dass Sie nicht so viel auf dem Bau zu tun, und als dritte Option können Sie mit einem Test Überlastung dieses Problem umgehen:

public class YourClass { 
    /** Public constructor for external access. */ 
    public YourClass() { 
    this(new Handler(Looper.getMainLooper())); 
    } 

    /** Package-private constructor for testing. */ 
    YourClass(Handler handler) { 
    init(handler); 
    } 

    private void init(Handler handler) { 
    handler.post(new Runnable() { 
     @Override public void run() { 
     //Some code 
     } 
    }); 
    } 
} 

Randbemerkung: Seien Sie besonders vorsichtig, dass init privat oder endgültig, weil it's dangerous to call overridable methods from constructors.