此单元测试失败。
package com.abc;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.net.URI;
import java.net.URL;
import static org.junit.Assert.assertEquals;
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PrepareForTest({URI.class})
public class ITest2 {
@Test
public void test5() throws Exception {
URI uri = new URI("http://www.google.com");
final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource("static/abc.png"); //EXISTS
PowerMockito.whenNew(URL.class).withArguments(
"http://www.google.com")
.thenReturn(resourceUrl);
URL url = uri.toURL(); // <--- At this point, url should be == resourceUrl
assertEquals(resourceUrl, url); // <--- url is http://www.google.com and not ".../static/abc.png"
}
}
此单元测试失败。
java.lang.AssertionError:
Expected :file:/Users/hidden/target/classes/static/abc.png
Actual :http://www.google.com
<Click to see difference>
你知道为什么 url != resourceUrl 吗?我错过了什么?
这是 URI.toURL() 的代码:
public URL toURL()
throws MalformedURLException {
if (!isAbsolute())
throw new IllegalArgumentException("URI is not absolute");
return new URL(toString());
}
使用 Mockito 2.15 和 Powermock 2.0.7。
谢谢。
更新:
添加这些也没有帮助。只是黑客攻击。
PowerMockito.whenNew(URL.class).withArguments(
eq("http://www.google.com"))
.thenReturn(resourceUrl);
PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(resourceUrl);
PowerMockito.whenNew(URL.class).withArguments(any()).thenReturn(resourceUrl);
PowerMockito.whenNew("java.net.URL").withArguments(any()).thenReturn(resourceUrl);
PowerMockito.whenNew(URL.class).withParameterTypes(String.class)
.withArguments("http://www.google.com")
.thenReturn(resourceUrl);
PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(resourceUrl);
PowerMockito.whenNew(URL.class).withNoArguments().thenReturn(resourceUrl);
最佳答案
来自FAQ :
Question:
I cannot mock classes in from java.lang, java.net, java.io or other system classes, why?
Answer:
This is because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. Since PowerMock 1.2.5 there's a work-around, please have a look at this simple example to see how it's done.
请注意,示例的链接已失效,应该是 this一个代替。
<小时/>user674669 写道:
I am intercepting the constructor of URL class which happens in URI class.
你正在尝试这样做。然而,这默默地失败了(并且创建了真实的对象)。
user674669 写道:
So, I am preparing URI using PrepareForTest annotation.
java.net.URI
是一个系统类。如上所述,PowerMockito 无法为其操作字节码,因此不会产生任何效果。您将必须调整不同类的字节码,这意味着您需要在 @PrepareForTest
注释中定义不同的类。
linked article 中提到的案例的工作示例:
使用powermock 2.0.7
、mockito 3.3.3
、junit 4
进行测试
public class ClassUnderTest {
public InputStream method(boolean param, URI uri) throws Exception {
String scheme = param ? "https" : "http";
URI replacedUri = new URI(scheme, uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment());
return replacedUri.toURL().openStream();
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassUnderTest.class)
public class MyTest {
@Test
public void testMethod() throws Exception {
URI uri = new URI("blah://localhost");
FileInputStream fis = new FileInputStream(new File(".", "existing.file"));
URI uriMock = PowerMockito.mock(URI.class);
URL urlMock = PowerMockito.mock(URL.class);
PowerMockito.whenNew(URI.class).withAnyArguments().thenReturn(uriMock);
Mockito.when(uriMock.toURL()).thenReturn(urlMock);
Mockito.when(urlMock.openStream()).thenReturn(fis);
ClassUnderTest testObject = new ClassUnderTest();
InputStream is = testObject.method(false, uri);
Assert.assertEquals(fis, is);
}
}
这是有效的,因为 ClassUnderTest
的字节码被修改了
并且定义的模拟被放置在那里,而不是创建真正的 URI
对象。
关于java - Powermockito 未在 URI.toURL() 方法中模拟 URL 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61239329/