我正在编写一些单元测试,并尝试从代码中覆盖尽可能多的内容。现在我想编写一个验证本地主机名称的测试。
方法如下:
public static String getLocalhostName() {
try {
return InetAddress.getLocalHost().getHostName();
}
catch ( final UnknownHostException e ) {
throw new RuntimeException( e.getMessage() );
}
}
和我的测试:
@Test
public void testGetLocalhostName() {
final String host = getLocalhostName();
Assert.assertEquals( "mycomputer", host );
}
问题是我如何重构这个以便覆盖主方法中的catch
块?
答案 0 :(得分:2)
@Test
public void testGetLocalhostName() {
String url = "http://hostname/xxxxx";
Throwable throwable = catchThrowable(() -> foo.getLocalHost(url));
assertThat(throwable)
.isNotNull()
.isInstanceOf(RuntimeException.class)
.hasMessage("your message");
assertThat(throwable.getCause()).isInstanceOf(UnknownHostException.class);
}
您可以通过这种方式测试异常类型,消息和测试主机名。
答案 1 :(得分:1)
根据经验,你不应该嘲笑外部库。通过嘲弄,您可以假设它的行为方式,可能不是这种情况或将来会发生什么变化。您应该只模拟您控制的代码和具有测试的代码。
在这种情况下,我会将InetAddress.getLocalHost().getHostName()
提取到另一个类HostNameProvider
,然后执行依赖注入,就像在John Williams'回答,但没有使用电源模拟。那么你将有两个测试当前的类和一个HostNameProvider
(只有快乐的路径)。
然而,在应用测试驱动开发时,在实践中会发生什么?你编写了一个测试,你编写实现并且它没有编译,所以你必须通过添加try-catch来修复它。在这一点上,我会依赖没有开发人员如此不负责任地吞下异常。如果有人这样做,你就会进行静态分析 - IntelliJ和Sonar都会强调这一点。简而言之 - 我不会测试它。
我还建议修改模板,因此当您生成try-catch时,它会自动在catch中添加throw new RuntimeException(e);
。
答案 2 :(得分:0)
这将为您提供测试覆盖率。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.net.InetAddress;
import java.net.UnknownHostException;
import static org.mockito.BDDMockito.given;
@RunWith(PowerMockRunner.class)
@PrepareForTest(InetAddress.class)
public class Mocker {
@Mock
private java.net.InetAddress mockedAddress;
@Test(expected = RuntimeException.class)
public void testGetLocalHostName() throws Exception {
//given
PowerMockito.mockStatic(InetAddress.class);
given(InetAddress.getLocalHost()).willReturn(mockedAddress);
given(mockedAddress.getHostName()).willThrow(UnknownHostException.class);
//when
getLocalhostName();
}
public static String getLocalhostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (final UnknownHostException e) {
throw new RuntimeException(e.getMessage());
}
}
}
但它并不令人满意,因为它不会在抛出RuntimeException
之前验证预期的代码是否已运行。
捕获异常可能会更好,然后您可以验证对模拟类的调用。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.net.InetAddress;
import java.net.UnknownHostException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
@RunWith(PowerMockRunner.class)
@PrepareForTest(InetAddress.class)
public class Mocker {
@Mock
private java.net.InetAddress mockedAddress;
@Test
public void testGetLocalHostName() throws Exception {
//given
PowerMockito.mockStatic(InetAddress.class);
given(InetAddress.getLocalHost()).willReturn(mockedAddress);
given(mockedAddress.getHostName()).willThrow(UnknownHostException.class);
//when
try {
getLocalhostName();
} catch (RuntimeException e) {
PowerMockito.verifyStatic();
InetAddress.getLocalHost();
verify(mockedAddress).getHostName();
}
}
public static String getLocalhostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (final UnknownHostException e) {
throw new RuntimeException(e.getMessage());
}
}
}
答案 3 :(得分:0)
我遇到了同样的问题,并提出了以下建议:
private static String getHostName() {
// unit test trickery!!!
// the TRY should simply return Inet4Address.getLocalHost().getHostName().
// but, there's no way to force an UnknownHostException, so we can't
// get 100% coverage. 100% coverage isn't entirely necessary, but it
// was the only uncovered line in the entire project, so let's make it happen.
// throw the exception manually and use it to propagate the host name to the
// catch, then the catch returns it. BOOM! Sorcery.
// This is only called once during the app life time, so we can take
// a hit on the unnecessary exception.
try {
throw new UnknownHostException(Inet4Address.getLocalHost().getHostName());
} catch (final UnknownHostException e) {
return e.getMessage();
}
}
它只使用了一次(结果被分配给一个变量,并且该变量被重用),所以我愿意承担道德冲击。
当然,如果确实存在异常,则不会进行区分。可以详细说明CATCH来解决这一问题。 (即:如果结果中有空格,则不是主机名)
答案 4 :(得分:-2)
public static String getLocalhostName() throws UnknownHostException {
try {
return InetAddress.getLocalHost().getHostName();
}
catch ( final UnknownHostException e ) {
throw new RuntimeException( e.getMessage() );
}
}
@Test
public void testGetLocalhostName() throws UnknownHostException {
final String host = getLocalhostName();
Assert.assertEquals( "mycomputer", host );
}
并在main中使用try..catch或声明它抛出Exception或UnKnownHostException