Search code examples
javaamazon-s3mockitojunit4powermock

Not able to mock java.net.URL even by using PowerMock?


According to my requirements, I have to upload a file to Amazon S3 by using pre-signed URL for which I got the code from the AWS website which worked for me but now I have to write JUnit for the same in which I used PowerMockito to mock java.net. URL but it's not working at all. Following is my Java code plus the JUnit which is not working. Can anyone give me solution on how should I proceed? Thanks in advance.
My code:-

public class App {
    public Boolean uploadToS3(String presignedUrl, String jsonBody) {
        try {
            URL url = new URL(presignedUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setRequestMethod("PUT");
            OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
            out.write(jsonBody);
            out.close();
            int responseCode = connection.getResponseCode();
            System.out.println("Service returned response code " + responseCode);
            return true;
        } catch (IOException io) {
            io.printStackTrace();
        }
        return false;
    }

}


JUnit

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({URL.class,HttpURLConnection.class,OutputStreamWriter.class,OutputStream.class})
public class AppTest
{
    @InjectMocks
    App app;

    @Test
    public void uploadToS3_should_return_true() throws Exception{
        App app = new App();
        //App app = PowerMockito.mock(App.class);
        URL url = PowerMockito.mock(URL.class);
        HttpURLConnection connection = PowerMockito.mock(HttpURLConnection.class);
        OutputStreamWriter outStreamWriter = PowerMockito.mock(OutputStreamWriter.class);
        OutputStream outStream = PowerMockito.mock(OutputStream.class);


        PowerMockito.whenNew(URL.class).withArguments(Matchers.anyString()).thenReturn(url);
        PowerMockito.when(url.openConnection()).thenReturn(connection);
        PowerMockito.whenNew(OutputStreamWriter.class).withArguments(Matchers.any()).thenReturn(outStreamWriter);
        PowerMockito.when(connection.getOutputStream()).thenReturn(outStream);
        PowerMockito.when(connection.getResponseCode()).thenReturn(201);
        app.uploadToS3("http://something.com", "{}");

    }
}


Solution

  • @InjectMocks
    App app;
    
    @Mock
    URL url;
    
    @Mock
    OutputStream outStream;
    
    @Test
    public void uploadToS3_should_return_true() throws Exception{
        // no need to create instance of App, it should be initialyzed fine with @InjectMocks annotation
        // define mocked behavior   
        HttpURLConnection connection = PowerMockito.mock(HttpURLConnection.class);
        // mock connection and out stream methods
        PowerMockito.when(url.openConnection()).thenReturn(connection);
        PowerMockito.whenNew(URL.class).withArguments(Matchers.anyString()).thenReturn(url);
    
        PowerMockito.when(connection.getOutputStream()).thenReturn(outStream);
        PowerMockito.when(connection.getResponseCode()).thenReturn(200);
    
        // call action
        app.uploadToS3("http://something.com", "{}");
    }