使用PowerMockito测试HttpURLConnection POST请求时遇参数异常
Alright, let's break down why you're hitting that IllegalArgumentException and fix it step by step:
What's Causing the Issue?
The error java.lang.IllegalArgumentException: type null is not compatible with address null comes from two key problems:
- Missing PowerMockito Configuration: You're trying to mock constructors of JDK classes like
URL,Proxy, andInetSocketAddress, but haven't set up PowerMockito properly to allow this. Without the right annotations, yourwhenNewcalls won't override real constructor logic, leading to unexpected null values. - Unmocked Proxy Methods: Even if you successfully mock the
Proxyobject, its default mock behavior returnsnullfor methods likegetType()andaddress(). WhenURL.openConnection(proxy)runs, the JDK's internal logic checks if the proxy's type and address are valid (non-null), triggering the exception.
Step-by-Step Fix
1. Add Required PowerMockito Annotations
First, your test class needs these annotations to enable mocking of JDK class constructors and control test execution:
@RunWith(PowerMockRunner.class) @PrepareForTest({HttpClient.class, URL.class, Proxy.class, InetSocketAddress.class}) public class HttpClientTest { // Your test code will go here }
@RunWith(PowerMockRunner.class): Tells JUnit to use PowerMock's custom test runner.@PrepareForTest: Lists all classes where you need to mock constructors or static methods (yourHttpClientclass plus the JDK classes you're mocking).
2. Mock Proxy's Critical Validation Methods
Add these lines after creating your mock Proxy to ensure it returns valid values for the JDK's checks:
// Mock Proxy's type and address to avoid null validation failures PowerMockito.when(proxy.getType()).thenReturn(Proxy.Type.HTTP); PowerMockito.when(proxy.address()).thenReturn(inetAddr);
3. Fix the makeRequest Method's Return Value
Your test expects a String response, but the current makeRequest method is void. Update it to return the collected response content:
public String makeRequest(String empid, JsonObject request) { JsonObject variables = request.getJsonObject("variables"); variables.put("requested_for", empid); request.put("variables", variables); StringBuffer response = new StringBuffer(); try { String url = "Some_valid_url"; URL obj = new URL(url); String proxyURL = "abc.xyz.com"; int port = 80; Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyURL, port)); HttpURLConnection con = (HttpURLConnection) obj.openConnection(proxy); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/json"); System.setProperty("com.sun.net.ssl.checkRevocation", "false"); // Disable SSL revocation check con.setDoOutput(true); DataOutputStream wr = new DataOutputStream(con.getOutputStream()); String requestBody = request.toString(); wr.writeBytes(requestBody); wr.flush(); wr.close(); BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); } catch (Exception e) { System.out.println(e); } // Return the assembled response string return response.toString(); }
4. Updated Test Code
Here's the full corrected test with all fixes applied, plus optional assertions to verify behavior:
public class HttpClientTest { private HttpClient impl; @Before public void setUp() { impl = new HttpClient(); } @Test public void httpClientTest() { try { URL obj = PowerMockito.mock(URL.class); Proxy proxy = PowerMockito.mock(Proxy.class); InetSocketAddress inetAddr = PowerMockito.mock(InetSocketAddress.class); HttpURLConnection mockConn = PowerMockito.mock(HttpURLConnection.class); BufferedReader mockReader = PowerMockito.mock(BufferedReader.class); // Mock constructor calls to return our mocked objects PowerMockito.whenNew(InetSocketAddress.class).withArguments(anyString(), anyInt()).thenReturn(inetAddr); PowerMockito.whenNew(URL.class).withArguments(any(String.class)).thenReturn(obj); PowerMockito.whenNew(Proxy.class).withArguments(Proxy.Type.HTTP, inetAddr).thenReturn(proxy); // Mock Proxy methods to pass JDK validation PowerMockito.when(proxy.getType()).thenReturn(Proxy.Type.HTTP); PowerMockito.when(proxy.address()).thenReturn(inetAddr); // Mock URL openConnection to return our mock HttpURLConnection PowerMockito.when(obj.openConnection(proxy)).thenReturn(mockConn); // Mock input stream to return a sample success response PowerMockito.when(mockConn.getInputStream()).thenReturn(new ByteArrayInputStream("{\"status\":\"success\"}".getBytes())); PowerMockito.when(mockReader.readLine()).thenReturn("{\"status\":\"success\"}", null); // Prepare test request object JsonObject req = new JsonObject(); req.add("variables", new JsonObject()); // Initialize to avoid NPE // Execute the test String response = impl.makeRequest("abc", req); System.out.println(response); // Optional: Verify the response is correct Assert.assertEquals("{\"status\":\"success\"}", response); } catch (Exception e) { e.printStackTrace(); } } }
Key Takeaways
- Never skip
@RunWith(PowerMockRunner.class)and@PrepareForTestwhen mocking JDK class constructors or static methods with PowerMockito. - When mocking JDK objects like
Proxy, always mock methods used for internal validation (likegetType()andaddress()) to avoid null-related exceptions. - Ensure your test and target method have consistent return types to avoid confusion and enable meaningful assertions.
内容的提问来源于stack exchange,提问作者ammy

