我有以下这种方法。
protected static String encode(String url) {
try {
url = URLEncoder.encode(url, StandardCharsets.UTF_8.toString());
} catch (Exception e) {
LOGGER.warn("exception occured while encoding url {}", url);
}
return url;
}
我无法为此提供junit测试,因为我无法模拟URLEncoder。这种方法可能有2种结果
我能够为第一个结果创建测试方法。您将如何为第二个结果创建测试方法?
答案 0 :(得分:1)
您可以使用PowerMockito
模拟静态方法。假设您帖子中的静态方法在名为HelloWorld
的类中,则这是两个测试,其中第一个测试测试的是肯定案例,第二个测试
正在测试例外情况:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.doThrow;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest(HelloWorld.class)
public class HelloWorldTest {
@Test
public void encode_returnsEncoded() throws UnsupportedEncodingException {
// given
mockStatic(URLEncoder.class);
when(URLEncoder.encode(any(String.class), any(String.class)))
.thenReturn("testUrlEncoded");
// when
String encoded = HelloWorld.encode("testUrl");
// then
assertThat(encoded).isEqualTo("testUrlEncoded");
}
@Test
public void encode_returnsInputOnException() {
// given
mockStatic(URLEncoder.class);
doThrow(new Exception("exception from test"))
.when(URLEncoder.class);
// when
String encoded = HelloWorld.encode("testUrl");
// then
assertThat(encoded).isEqualTo("testUrl");
}
}
答案 1 :(得分:1)
软件工程的基本定理(FTSE)是由安德鲁·科尼格(Andrew Koenig)提出的,用于描述巴特勒·兰普森(Butler Lampson)对已故戴维·J·惠勒(David J. Wheeler)的评价:
“我们可以通过引入额外的间接级别来解决任何问题。”
[...]
该定理通常由幽默的子句“ ...,除了太多的间接级别的问题外,”,它指的是太多的抽象可能会产生其自身固有的复杂性问题。 (来源:Wikipedia)
因此,假设有一个类具有名为encode
的静态方法:
public final class UrlHelper {
protected static String encode(String url) {
try {
url = URLEncoder.encode(url, StandardCharsets.UTF_8.toString());
} catch (Exception e) {
LOGGER.warn("exception occured while encoding url {}", url);
}
return url;
}
}
并且您的代码取决于它:
public class MyClass {
public void doSomething(String someUrl) {
// ...
String encodedUrl = UrlHelper.encode(someUrl);
// ...
}
}
,您想测试MyClass.doSomething(String someUrl)
,但想模拟UrlHelper.encode(someUrl)
。一种选择是定义另一个类,例如
public final class MyUrlHelper {
protected String encode(String url) {
return UrlHelper.encode(someUrl);
}
}
由于MyUrlHelper.encode(String url)
不是静态的,因此您可以重构原始代码并通过依赖注入和模拟非静态的MyUrlHelper.encode(String url)
来对其进行测试:
// Refactored
public class MyClass {
private MyUrlHelper myUrlHelper;
public UrlHelper(MyUrlHelper muUrlHelper) {
this.myUrlHelper = myUrlHelper;
}
public void doSomething(String someUrl) {
// ...
String encodedUrl = myUrlHelper.encode(someUrl);
// ...
}
}
// Test
@Test
public void myTest() {
// setup myUrlHelper and configure it
MyUrlHelper myUrlHelper = mock(MyUrlHelper.class);
when(myUrlHelper.encode(...)).thenReturn(...);
// inject
MyClass myObject = new MyClass(myUrlHelper);
// stimulate
myObject.doSomething("...")
}
另一种选择是使用PowerMockRunner使用Mockito,如 @Marimuthu Madasamy 所述。
但是,在这里模拟UrlHelper.encode
或URLEncoder.encode
并没有任何好处。它不是外部系统(数据库,文件系统,消息代理,SOAP API,REST API等),因此我看不到通过模拟获得任何好处。
答案 2 :(得分:0)