我正在尝试使用PowerMockito来模拟我正在测试的代码中创建java.net.URL类。 基本上,我想阻止真正的HTTP请求发生,而是1)在发出请求时检查数据,2)在模拟响应上提供我自己的测试数据。 这就是我正在尝试的:
@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);
...
}
我要测试的代码如下所示:
URL wlInvokeUrl = new URL(wlInvokeUrlString);
connection = (HttpURLConnection) wlInvokeUrl.openConnection();
在我的测试场景中,我模拟了wlInvokeUrlString以匹配"MyURLString"。 我还尝试使用各种其他形式的 whenNew 行,尝试注入模拟。 无论我尝试什么,它都不会拦截构造函数。 我想做的只是"捕获"对 openConnection() 的调用,并让它返回我模拟的 HTTP 连接而不是真正的连接。
我已经在同一脚本中模拟了这个类之前的其他类,这些类按预期工作。 要么我需要第二双眼睛(可能是真的),要么 URL 类有一些独特的东西。 我确实注意到,如果我使用"whenNew(URL.class).withAnyArguments()"并将"thenReturn"更改为"thenAnswer",我可以触发它。 唯一的问题是我从来没有收到我的代码的 URL 调用。 我看到的是 URL 的 3 参数构造函数的调用.class参数的所有空值。 可能是这个类来自 Java 运行时并且由测试运行器引导吗? 任何帮助都非常感谢。
这是使用 PowerMockito.whenNew
时的常见错误。
请注意,您必须准备创建 MyClass 新实例的类进行测试,而不是 MyClass 本身。 例如,如果执行新MyClass()的类称为X,那么您必须执行@PrepareForTest(X.class)才能使何时New 工作
来自Powermock wiki
因此,您需要稍微更改一下测试并添加到@PrepareForTest
创建一个类,该类创建URL
的新实例,例如:
@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());
}
}
哪里:
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;
}
}
我不确定.withParameterTypes(x)
和.withArguments(x)
之间的区别,但我相信您需要对其进行如下设置才能使代码正常工作。试一试,如果这没有帮助,请告诉我。
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(mockedURL);
问题是真实调用的参数与模拟中的预期不匹配。
PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL)
将返回mockedURL
只有呼叫new URL("MyURLString")
。
如果将其更改为:
PowerMockito.whenNew( URL.class ).withParameterTypes( String.class )
.withArguments( org.mockito.Matchers.any( String.class ) ).thenReturn( mockedURL );
它将捕获传递给构造函数的任何字符串URL(String)
(甚至null
)并返回您的模拟。
当您尝试时
"whenNew(URL.class).withAnyArguments()"并将"thenReturn"更改为 "那么答案"我可以让它触发。唯一的问题是我永远不会得到 我的代码的 URL 调用。我看到的是 URL 的 3 参数构造函数.class所有空值为 参数。
PowerMock 将尝试模拟所有构造函数(org.powermock.api.mockito.internal.expectation.DelegatingToConstructorsOngoingStubbing.InvokeStubMethod
在第 122 行),然后调用第一个构造函数(有 3 个参数)并模拟其答案。但是后续调用将返回已经模拟的调用,因为您告诉它模拟任何参数。这就是为什么您在Answer
中只看到一个带有null, null, null
的呼叫。