2016-08-06 10 views
0

私はURLを取って、getリクエストを介してこのURLからデータを取得する簡単な方法を書いています。このメソッドは次のようになります。PowerMockが正しく模倣しない

public String getResponse(String connectionUrl) throws HttpException { 

    HttpURLConnection connection = null; 

    try { 
     URL url = new URL(connectionUrl); 
     connection = (HttpURLConnection) url.openConnection(); 
     connection.setRequestMethod("GET"); 

     int responseCode = connection.getResponseCode(); 
     if (responseCode != 200) { 
      throw new HttpException("Response code was " + responseCode + " (should be 200)"); 
     } 

     Scanner scanner = new Scanner(connection.getInputStream()).useDelimiter("\\A"); 
     String response = scanner.hasNext() ? scanner.next() : ""; 

     connection.disconnect(); 
     scanner.close(); 

     return response; 

    } catch (IOException e) { 

     if (connection != null) { 
      connection.disconnect(); 
     } 

     throw new HttpException(e.getMessage(), e.getCause()); 
    } 
} 

このメソッドの単体テストを記述しています。私はMockitoとJUnitでPowerMockを使ってテストを書いています。問題のテストは、次のようになります。

@Test 
public void getResponse_NormalResponse() throws Exception { 

    String expectedResponse = "This is the expected response text!"; 
    URL url = PowerMockito.mock(URL.class); 
    HttpURLConnection connection = PowerMockito.mock(HttpURLConnection.class); 
    InputStream inputStream = PowerMockito.mock(InputStream.class); 
    Scanner scanner = PowerMockito.mock(Scanner.class); 

    PowerMockito.whenNew(URL.class).withArguments(REQUEST_URL).thenReturn(url); 
    PowerMockito.whenNew(Scanner.class).withArguments(inputStream).thenReturn(scanner); 
    PowerMockito.when(url.openConnection()).thenReturn(connection); 

    // Response code mocked here 
    PowerMockito.when(connection.getResponseCode()).thenReturn(200); 

    PowerMockito.when(connection.getInputStream()).thenReturn(inputStream); 
    PowerMockito.when(scanner.hasNext()).thenReturn(true); 
    PowerMockito.when(scanner.next()).thenReturn(expectedResponse); 

    HttpClient httpClient = new HttpClient(); 
    String actualResponse = httpClient.getResponse(REQUEST_URL); 

    Assert.assertEquals("Response is wrong!", expectedResponse, actualResponse); 
} 

しかし、私は、テストを実行すると応答コードはテストがPowerMockRunnerで実行されている404であるので、HttpExceptionがスローされます。何が間違っていたのですか、なぜこのテストは正しく動作していませんか?あなたは(あなたがwhenNewを使用し、各クラスの)オブジェクトの作成をモックとしたいとき、それぞれのケースのためにそれを追加する必要があり

@PrepareForTest({URL.class, Scanner.class}) 

+0

私は、PowerMockなしでテストできるようにメソッドコードをリファクタリングすることをお勧めします。多くの変更はありません。 –

+0

変更することをお勧めしますか? –

+0

ヒント:PowerMockを使用するのではなく、他のより理想的なアイデアは、単にあなたのメソッドで新しい呼び出しを行わない**ことです。テストするのが難しいコードを作成すると、テストするのが難しいときは驚かないでください。 https://www.youtube.com/playlist?list=PLD0011D00849E1B79 – GhostCat

答えて

1

whenNewを使用しているので、@PrepareForTestの下に新しいオブジェクトが作成されるクラスも追加する必要があります。

あなたのクラスはHttpClientを

@PrepareForTest({ URL.class, Scanner.class ,HttpClient.class}) 

のようですが、あなたのテストで1つのより多くの問題を解決しました。 不足している期待を追加しました。

出典:

public class HttpClient { 

    public String getResponse(String connectionUrl) throws HttpException { 

     HttpURLConnection connection = null; 

     try { 
      URL url = new URL(connectionUrl); 
      connection = (HttpURLConnection) url.openConnection(); 
      connection.setRequestMethod("GET"); 

      int responseCode = connection.getResponseCode(); 
      if (responseCode != 200) { 
       throw new HttpException("Response code was " + responseCode 
         + " (should be 200)"); 
      } 

      Scanner scanner = new Scanner(connection.getInputStream()) 
        .useDelimiter("\\A"); 
      String response = scanner.hasNext() ? scanner.next() : ""; 

      connection.disconnect(); 
      scanner.close(); 

      return response; 

     } catch (IOException e) { 

      if (connection != null) { 
       connection.disconnect(); 
      } 

      throw new HttpException(e.getMessage(), e.getCause()); 
     } 
    } 

} 

class HttpException extends Exception { 

    public HttpException(String string) { 
     super(string); 
    } 

    public HttpException(String message, Throwable cause) { 
     super(message, cause); 
    } 

} 

テストケース:私が使用しているポンポンを取り付け

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ URL.class, Scanner.class, HttpClient.class }) 
public class HttpClientTest { 

    private static final String REQUEST_URL = "http://wwww.google.com"; 

    @Test 
    public void getResponse_NormalResponse() throws Exception { 

     String expectedResponse = "This is the expected response text!"; 
     URL url = PowerMockito.mock(URL.class); 
     HttpURLConnection connection = PowerMockito 
       .mock(HttpURLConnection.class); 
     InputStream inputStream = PowerMockito.mock(InputStream.class); 
     Scanner scanner = PowerMockito.mock(Scanner.class); 

     PowerMockito.whenNew(URL.class).withArguments(REQUEST_URL) 
       .thenReturn(url); 
     PowerMockito.whenNew(Scanner.class).withArguments(inputStream) 
       .thenReturn(scanner); 
     PowerMockito.when(scanner.useDelimiter("\\A")).thenReturn(scanner); 

     PowerMockito.when(url.openConnection()).thenReturn(connection); 

     // Response code mocked here 
     PowerMockito.when(connection.getResponseCode()).thenReturn(200); 

     PowerMockito.when(connection.getInputStream()).thenReturn(inputStream); 
     PowerMockito.when(scanner.hasNext()).thenReturn(true); 
     PowerMockito.when(scanner.next()).thenReturn(expectedResponse); 

     HttpClient httpClient = new HttpClient(); 
     String actualResponse = httpClient.getResponse(REQUEST_URL); 

     Assert.assertEquals("Response is wrong!", expectedResponse, 
       actualResponse); 
    } 
} 

PowerMockito.when(scanner.useDelimiter("\\A")).thenReturn(scanner); 

は動作するコードを修正しました。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>MockItToExample</groupId> 
    <artifactId>MockItToExample</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 

    <dependencies> 

     <dependency> 
      <groupId>org.mockito</groupId> 
      <artifactId>mockito-all</artifactId> 
      <version>1.10.19</version> 

     </dependency> 

     <!-- https://mvnrepository.com/artifact/junit/junit --> 
     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>4.12</version> 
     </dependency> 

     <dependency> 
      <groupId>org.powermock</groupId> 
      <artifactId>powermock-module-junit4</artifactId> 
      <version>1.6.3</version> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>org.powermock</groupId> 
      <artifactId>powermock-api-mockito</artifactId> 
      <version>1.6.3</version> 
     </dependency> 

    </dependencies> 

    <build> 
     <sourceDirectory>src</sourceDirectory> 
     <plugins> 
      <plugin> 
       <artifactId>maven-compiler-plugin</artifactId> 
       <version>3.1</version> 
       <configuration> 
        <source>1.7</source> 
        <target>1.7</target> 
       </configuration> 
      </plugin> 
     </plugins> 
    </build> 
</project> 
+0

私はあなたのコードを実装しましたが、それは私のためには機能しませんでした。実際に存在するURL(google.com)を指定したためです。接続は嘲笑されず、テストは実際にサーバーに接続します。しかし、私はインターネット接続なしでもテストが動作するように、http接続を嘲笑したい。それは不可能ですか? –

+0

こんにちは、\t私は静的最終的な文字列を試してREQUEST_URL = "http://www.test.com";それでも動作します。 –

+0

期待どおりの応答を返しますか? (これは期待される応答テキストです)。どのテストランナーでテストを実行しますか? –

0

をして、あなたのテストクラスに注釈を付けます。

+0

ありがとうございます、私は行を追加しましたが、テストの結果はまだ同じです –

関連する問題