我正在尝试使用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()"并改变"然后返回" to" thenAnswer"我可以让它触发。唯一的问题是我从来没有得到我的代码的URL调用。我看到的是对URL.class的3参数构造函数的调用以及参数的所有空值。难道这个类来自Java运行时并且由测试运行器引导?非常感谢任何帮助。
答案 0 :(得分:1)
使用PowerMockito.whenNew
时常见的错误。
请注意,您必须准备创建MyClass的新实例的类,而不是MyClass本身。例如。如果执行新MyClass()的类被称为X,那么你必须执行@PrepareForTest(X.class)才能使newNew工作
因此,您需要稍微更改一下测试并添加到@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;
}
}
答案 1 :(得分:0)
我不确定.withParameterTypes(x)
和.withArguments(x)
之间的区别,但我相信您需要按照以下步骤进行设置才能使代码正常工作。尝试一下,如果这没有用,请告诉我。
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(mockedURL);
答案 2 :(得分:0)
问题是真实调用的参数与模拟中的预期不匹配。
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()"并改变"然后返回"至 " thenAnswer"我可以让它触发。唯一的问题是我永远不会得到 我的代码的URL调用。我所看到的是对...的调用 URL.class的3参数构造函数,包含所有空值 参数。
PowerMock将尝试模拟所有构造函数(第122行的org.powermock.api.mockito.internal.expectation.DelegatingToConstructorsOngoingStubbing.InvokeStubMethod
),然后调用第一个(带有3个参数)并模拟其答案。但随后的调用将返回已经被模拟过的调用,因为你告诉它模拟任何参数。这就是为什么您在null, null, null
中只看到一个Answer
来电的原因。