2016-02-19 11 views
5

Ich versuche PowerMockito zu verwenden, um die Erstellung der Klasse java.net.URL in meinem Code, den ich gerade teste, zu verspotten. Im Grunde möchte ich verhindern, dass die echte HTTP-Anfrage auftritt, und stattdessen 1) die Daten überprüfen, wenn die Anfrage gemacht wird, und 2) meine eigenen Testdaten mit einer verspotteten Antwort zurückliefern. Das ist, was ich versuche:URL kann nicht mit PowerMockito/Mockito simuliert werden

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ URL.class, MockedHttpConnection.class }) 
public class Test { 
    URL mockedURL = PowerMockito.mock(URL.class); 
    MockedHttpConnection mockedConnection = PowerMockito.mock(MockedHttpConnection.class); 

... 
    PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL); 
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection); 

... 
} 

Der Code, den ich wie folgt aussieht testen will:

URL wlInvokeUrl = new URL(wlInvokeUrlString); 
connection = (HttpURLConnection) wlInvokeUrl.openConnection(); 

Früher in meinem Testszenario verspotten ich das wlInvokeUrlString „MyURLString“ entsprechen. Ich habe auch versucht, verschiedene andere Formen der whenNew-Linie zu verwenden, versuchend, den Schein zu injizieren. Egal was ich versuche, es fängt niemals den Konstruktor ab. Alles, was ich tun will, ist, den Aufruf von openConnection() zu fangen und meine gespottete HTTP-Verbindung anstelle der echten zurückgeben zu lassen.

Ich habe andere Klassen vor diesem im selben Skript verspottet und diese funktionieren wie erwartet. Entweder brauche ich ein zweites Augenpaar (wahrscheinlich wahr) oder es gibt etwas Einzigartiges an der URL-Klasse. Ich habe bemerkt, dass ich, wenn ich "whenNew (URL.class) .withAnyArguments()" benutze und den "thenReturn" in "thenAnswer" ändere, es auslösen könnte. Das einzige Problem ist, dass ich nie den URL-Aufruf für meinen Code bekomme. Was ich sehe, ist ein Aufruf des 3-Argument-Konstruktors für URL.class mit allen Nullen für die Parameter. Könnte es sein, dass diese Klasse von der Java Runtime stammt und vom Test Runner bootstrapped wird? Jede Hilfe wird sehr geschätzt.

+0

Sie benötigen keinen Powermock, um dies zu testen. Spotten Sie einfach die String-URL, um beispielsweise einen dateibasierten Pfad zu verwenden ("file: //my-test.properties"). Das funktioniert, und Sie können die Daten weitergeben, die Sie benötigen. –

+0

@ JérémieB Können Sie das etwas genauer ausführen? Dies scheint eine elegante und einfache Lösung zu sein, aber der getestete Code erwartet eine HttpURLConnection und ich erhalte eine ClassCastException, wenn ich die URL-Zeichenfolge ändere, um auf eine Datei zu verweisen (zB java.lang.ClassCastException: sun.net.www.protocol. ftp.FtpURLConnection kann nicht in java.net.HttpURLConnection umgewandelt werden. Wie würden Sie die Eingabeparameter für die Anfrage mithilfe dieses Ansatzes überprüfen? – Jim

+0

Sie sollten nicht direkt 'HttpURLConnection', sondern' URL' und 'URLConnection' verwenden. Es gibt nichts nützliches in 'HttpURLConnection'. Es ist der Zweck einer URL, die Transportschicht zu abstrahieren. –

Antwort

0

Ich bin mir nicht sicher, der Unterschied zwischen .withParameterTypes(x) und .withArguments(x), aber ich glaube, Sie müssen es einrichten, wie folgt für Ihren Code zu arbeiten. Probieren Sie es aus und lassen Sie es mich wissen, wenn das nicht hilft.

PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection); 
PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(mockedURL); 
+0

Ich habe diese Zeilen versucht, aber ich sehe die gleichen Ergebnisse. Anstatt die Mocked-Objekte zu verwenden, werden die Klassen real URL und HttpURLConnection erstellt und verwendet. Könnte das Problem damit zusammenhängen, dass die URL-Klasse als final deklariert ist? Nach dem, was ich gelesen habe, sollte PowerMockito damit umgehen können. – Jim

0

Das Problem besteht darin, dass die Argumente des tatsächlichen Aufrufs nicht mit dem erwarteten in Ihrem Schein übereinstimmen.

PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL) wird zurückgegeben mockedURL nur der Anruf ist new URL("MyURLString").

Wenn Sie es ändern:

PowerMockito.whenNew(URL.class).withParameterTypes(String.class) 
    .withArguments(org.mockito.Matchers.any(String.class)).thenReturn(mockedURL); 

wird es fangen beliebige Zeichenfolge an den Konstruktor übergeben URL(String) (auch null) und Ihr Mock zurück.


Wenn Sie versucht

"whenNew (URL.class) .withAnyArguments()" und die "thenReturn" zu ändern "thenAnswer" Ich kann es auslösen bekommen könnte. Das einzige Problem ist, dass ich nie den URL-Aufruf für meinen Code bekomme. Was ich sehe, ist ein Aufruf des 3-Argument-Konstruktors für URL.class mit allen Nullen für die Parameter.

PowerMock werden versuchen all Bauer (org.powermock.api.mockito.internal.expectation.DelegatingToConstructorsOngoingStubbing.InvokeStubMethod in Zeile 122), dann ruft er die ersten zu verspotten (mit 3 Argumenten) und seine Antwort verspotten. Aber die nachfolgenden Aufrufe werden die bereits gespotteten zurückgeben, weil Sie es für Argumente verspotten. Deshalb sehen Sie nur einen Anruf mit null, null, null in Ihrem Answer.

+0

Ich habe viele Dinge im Laufe des Versuchs versucht, um dies zu machen, einschließlich einer Variation Ihres Vorschlags. Ich habe erneut getestet, indem ich die Zeile whenNew wie erwähnt geändert habe, aber immer noch die gleichen Ergebnisse erzielt habe. Irgendwelche anderen Gedanken? – Jim

0

Es ist ein häufiger Fehler bei der Verwendung PowerMockito.whenNew.

Beachten Sie, dass Sie die Klasse vorbereiten müssen, die die neue Instanz von MyClass für Test erstellt, nicht die MyClass selbst. Z.B. wenn die Klasse neue MyClass tun() aufgerufen wird X dann würden Sie tun müssen, um @PrepareForTest (X.class), um für whenNew zu

arbeiten

Von Powermock wiki

So müssen Sie ein wenig ändern Ihr Test und eine Klasse @PrepareForTest hinzufügen, die eine neue Instanz von URL erstellen möchten:

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ URL.class, MockedHttpConnection.class , ConnectionUser.class}) 
public class URLTest { 
public class URLTest { 

    private ConnectionUser connectionUser; 

    @Before 
    public void setUp() throws Exception { 

     connectionUser = new ConnectionUser(); 
    } 

    @Test 
    public void testName() throws Exception { 

     URL mockedURL = PowerMockito.mock(URL.class); 
     MockedHttpConnection mockedConnection = PowerMockito.mock(MockedHttpConnection.class); 

     PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL); 
     PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection); 

     connectionUser.open(); 

     assertEquals(mockedConnection, connectionUser.getConnection()); 


    } 
} 

wo:

public class ConnectionUser { 

    private String wlInvokeUrlString = "MyURLString"; 
    private HttpURLConnection connection; 

    public void open() throws IOException { 
     URL wlInvokeUrl = new URL(wlInvokeUrlString); 
     connection = (HttpURLConnection) wlInvokeUrl.openConnection(); 
    } 

    public HttpURLConnection getConnection() { 
     return connection; 
    } 
} 
+0

Ihre Antwort kommt der Arbeit am nächsten. Nach diesen Änderungen wird der Schein-URL-Konstruktor aufgerufen. Es gibt jedoch immer ein Null-Objekt zurück. Damit meine ich die Zeile URL wlInvokeUrl = new URL (wlInvokeUrlString); weist wlInvokeUrl immer null zu. Ich habe das ursprüngliche Problem behoben, indem ich meinen Code umgestaltet habe, aber ich bin immer noch damit beschäftigt, PowerMockito dafür zu verwenden, falls Sie andere Vorschläge haben. – Jim

+0

Welche Versionen von PowerMock, Mockito, Java verwenden Sie? Ich habe mit der neuesten Version und Mockito 1.10.19 getestet und kann dein Problem nur reproduzieren, wenn ich 'mockedUrl'via' null' ersetze. Wie folgt: 'PowerMockito.whenNew (URL.class) .withArguments (" MyURLString "). ThenReturn (null);' In allen anderen Fällen wird meine Testversion übergeben. Übrigens verwende ich Java 8, um den Test auszuführen. –

+0

Könnten Sie versuchen, meine Version in Ihrer Umgebung auszuführen? –