Java Junit test HTTP POST request

六月ゝ 毕业季﹏ 提交于 2021-02-18 20:30:14

问题


I need to test the following method with out altering the method itself. The method makes a POST method to a server. But I need to make a test case that's independent from the server.

I tested a similar method before redirecting it to a local file. But that for that I was giving protocol as file, hostname as localhost and port as -1.

My problem is that this method does a post and casts to HttpURLConnection and wr = new DataOutputStream(conn.getOutputStream()); wont work on an local txt file through http.

//the constructor

public HTTPConnector(String usr, String pwd, String protocol,
            String hostname, int port) {
        this.usr = usr;
        this.pwd = pwd;
        this.protocol = protocol;
        this.hostname = hostname;
        this.port = port;

        // connect();
    }

//the method I need to test

public String doPost(String reference, String data) throws IOException {
        URL url = null;
        HttpURLConnection conn = null;
        BufferedReader rd = null;
        DataOutputStream wr = null;
        InputStream is = null;
        String line = null;
        StringBuffer response = null;

        url = new URL(protocol, hostname, port, reference);
        conn = (HttpURLConnection) url.openConnection();

        conn.setRequestMethod("POST");

        conn.setRequestProperty("Authorization", "Basic dGVzdDphc2Rm");
        conn.setRequestProperty("Content-Type", "application/xml");

        conn.setUseCaches(false);
        conn.setDoInput(true);
        conn.setDoOutput(true);

        // Send response
        wr = new DataOutputStream(conn.getOutputStream());
        wr.writeBytes(data);
        wr.flush();
        wr.close();

        // Get response
        is = conn.getInputStream();
        rd = new BufferedReader(new InputStreamReader(is));
        response = new StringBuffer();
        while ((line = rd.readLine()) != null) {
            response.append(line);
            response.append('\r');
        }
        rd.close();
        return response.toString();
    }

//the method I could test

public String doGet(String reference) throws IOException {
        connect();
        URL url = new URL(protocol, hostname, port, reference);
        InputStream content = (InputStream) url.getContent();

        BufferedReader xml = new BufferedReader(new InputStreamReader(content));
        return xml.readLine();
    }

回答1:


Here's a sample test. Note that assertions I made are for demo purposes, you need to adapt to your needs.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ toTest.class, URL.class, HttpURLConnection.class })
public class soTest {
    /**
     * test response.
     */
    private static final String TEST_RESPONSE = "test\nresponse";

    /**
     * test data.
     */
    private static final String DATA = RandomStringUtils.randomAscii(125);

    /**
     * test port.
     */
    private static final int PORT = 8080;

    /**
     * test hosts.
     */
    private static final String HOSTNAME = "hostname";

    /**
     * test protocol.
     */
    private static final String PROTOCOL = "http";

    /**
     * test reference.
     */
    private static final String REFERENCE = "REFERENCE";

    /**
     * URL mock.
     */
    private URL url;

    /**
     * HttpURLConnection mock.
     */
    private HttpURLConnection connection;

    /**
     * Our output.
     */
    private ByteArrayOutputStream output;

    /**
     * Our input.
     */
    private ByteArrayInputStream input;

    /**
     * Instance under tests.
     */
    private toTest instance;

    @Before
    public void setUp() throws Exception
    {
        this.url = PowerMockito.mock(URL.class);
        this.connection = PowerMockito.mock(HttpURLConnection.class);

        this.output = new ByteArrayOutputStream();
        this.input = new ByteArrayInputStream(TEST_RESPONSE.getBytes());
        this.instance = new toTest(PROTOCOL, HOSTNAME, PORT);

        PowerMockito.whenNew(URL.class).withArguments(PROTOCOL, HOSTNAME, PORT, REFERENCE).thenReturn(this.url);
    }

    @Test
    public void testDoPost() throws Exception
    {
        PowerMockito.doReturn(this.connection).when(this.url).openConnection();
        PowerMockito.doReturn(this.output).when(this.connection).getOutputStream();
        PowerMockito.doReturn(this.input).when(this.connection).getInputStream();

        final String response = this.instance.doPost(REFERENCE, DATA);

        PowerMockito.verifyNew(URL.class);
        new URL(PROTOCOL, HOSTNAME, PORT, REFERENCE);

        // Mockito.verify(this.url).openConnection(); // cannot be verified (mockito limitation) 
        Mockito.verify(this.connection).getOutputStream();
        Mockito.verify(this.connection).setRequestMethod("POST");
        Mockito.verify(this.connection).setRequestProperty("Authorization", "Basic dGVzdDphc2Rm");
        Mockito.verify(this.connection).setRequestProperty("Content-Type", "application/xml");
        Mockito.verify(this.connection).setUseCaches(false);
        Mockito.verify(this.connection).setDoInput(true);
        Mockito.verify(this.connection).setDoOutput(true);
        Mockito.verify(this.connection).getInputStream();

        assertArrayEquals(DATA.getBytes(), this.output.toByteArray());
        assertEquals(TEST_RESPONSE.replaceAll("\n", "\r") + "\r", response);
    }
}


@Data
public class toTest {
    private final String protocol, hostname;

    private final  int port;

    public String doPost(String reference, String data) throws IOException
    {
        // your method, not modified
    }
}

dependencies:

  • commons-lang 2.5
  • powermock-api-mockito 1.4.11
  • powermock-module-junit4 1.4.11
  • junit 4.10
  • lombok 0.11.0 on tested class



回答2:


If you don't have the opportunity to refactor the method under test, then a novel approach would be to mock the HttpUrlConnection that it uses. At first hand this would appear to be difficult because the HttpUrlConnection is not passed in as a parameter. However, you can control this by controlling the connection returned from url.openConnection.

This is governed by the protocol handler registered with java.net.URL for the protocol that you pass to the constructor. The trick is to register a new protocol handler (see Java - Registering custom URL protocol handlers for details).

Your new protocol handler should return a mocked HttpUrlConnection that you can then use in your test.



来源:https://stackoverflow.com/questions/10635394/java-junit-test-http-post-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!