英文:
How to test that catch (Exception e) { e.printStackTrace();} invoked
问题
我需要达到95%的测试覆盖率(我的任务)。我在以下类中遇到了问题:
public class Context {
public static <T> T getObject(Class<T> clazz) {
Object bean = null;
try {
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) bean;
}
private Context() {
}
}
要达到95%的覆盖率,我需要验证在抛出异常时是否调用了 `e.printStackTrace();`。
我尝试了不同的方法,但它们都不起作用。我会感激任何支持。
英文:
I need to reach 95% test coverage (my task). I have problems with following class
public class Context {
public static <T> T getObject(Class<T> clazz) {
Object bean = null;
try {
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) bean;
}
private Context() {
}
}
to reach 95% I need to check that e.printStackTrace();
invoked when Exception thrown.
I tried different ways but none of them work. I will appreciate any support.
答案1
得分: 1
为了验证printStackTrace
是否被调用,我能想到的最简单的方法是使用一个间谍/模拟的Exception
对象。
使用Mockito,你可以传递一个模拟的Class
,当调用newInstance
时会抛出一个间谍Exception
。
Class<?> mockClass = mock(Class.class);
Exception e = Mockito.spy(new Exception());
Mockito.doThrow(e).when(mockClass).newInstance();
context.getObject(mockClass);
Mockito.verify(e).printStackTrace();
如果你知道Exception
会在哪里抛出(以便你可以使用@PrepareForTest
来准备该类),你还可以使用PowerMock和whenNew
来实现一些操作。
Exception e = Mockito.spy(new Exception());
PowerMockito.whenNew(Exception.class).thenReturn(e);
context.getObject(SomeService.class);
Mockito.verify(e).printStackTrace();
注意:我尚未编译和测试上述任何一种方法(而且在不同的地方,我一直将Mockito
和PowerMockito
类名拼写错误)。
如果你坚决要在不使用库的情况下进行,你可以这样做:
- 创建一个自定义的
Exception
类型,在调用该方法时明确设置一些标志: - 创建一个自定义的
class
,当调用无参构造函数时抛出上述的Exception
。 - 将这个自定义类的
.class
传递到你的方法中,并验证标志是否已经设置。
类似于:
class MyException extends Exception {
public static boolean printStackTraceCalled = false;
@Override
public void printStackTrace() {
MyException.printStackTraceCalled = true;
super.printStackTrace();
}
}
class MyClass {
MyClass() {
throw new MyException();
}
}
@Test
void testThing() {
context.getObject(MyClass.class);
Assertions.assertTrue(MyException.printStackTraceCalled);
}
话虽如此,这只是实现的方法... 我并不是说这是一个好主意。这是处理Exception
的不好方式,而且针对特定的代码覆盖率百分比进行目标设置往往是没有意义的。
英文:
To verify that printStackTrace
is called, the easiest way I can think of is a spy/mock Exception
object.
Using mockito, you could pass in a mock Class
which throws a spy Exception
when newInstance
is called.
Class<?> mockClass = mock(Class.class);
Exception e = Mockito.spy(new Exception());
Mockito.doThrow(e).when(mockClass).newInstance();
context.getObject(mockClass);
Mockito.verify(e).printStackTrace();
You could also do something with powermock and whenNew
if you know where the Exception
is going to be thrown (so that you can @PrepareForTest
that class).
Exception e = Mockito.spy(new Exception());
PowerMockito.whenNew(Exception.class).thenReturn(e);
context.getObject(SomeService.class);
Mockito.verify(e).printStackTrace();
Note: I have not compiled and tested either of the above (and consistently get the Mockito
and PowerMockito
class names wrong in various ways).
If you're dead-set on doing this without a library you could do something like:
- Create a custom
Exception
type, which explicitly sets some flag when that method is called: - Create a custom
class
which throws the aboveException
when the no-arg constructor is called. - Pass the
.class
of this custom class into your method, and verify that the flag has been set.
Something like:
class MyException extends Exception {
public static boolean printStackTraceCalled = false;
@Override
public void printStackTrace() {
MyException.printStackTraceCalled = true;
super.printStackTrace();
}
}
class MyClass {
MyClass() {
throw new MyException();
}
}
@Test
void testThing() {
context.getObject(MyClass.class);
Assertions.assertTrue(MyException.printStackTraceCalled);
}
That said, that's just how you would do this... I'm not saying this is a good idea. That's a bad way to handle Exception
s and targeting a specific % code-coverage is more often than not meaningless.
答案2
得分: 0
这是我解决这个问题的方式。我稍微重构了代码:
private static final Logger LOGGER = Logger.getLogger(Context.class.getName());
public <T> T getObject(Class<T> clazz) {
T bean = null;
try {
bean = clazz.getConstructor().newInstance();
} catch (Exception e) {
LOGGER.log(Level.INFO, e, () -> "在创建 " + clazz.getName() + " 时发生异常");
}
return bean;
}
这是测试部分:
@Test
void getObject_ShouldThrowException() throws Exception {
Exception mockedException = mock(InstantiationException.class);
Logger mockedLogger = mock(Logger.class);
class Dummy {
public Dummy() throws Exception {
throw mockedException;
}
}
try {
Dummy dummy = context.getObject(Dummy.class);
} catch (Exception e) {
verify(mockedLogger, times(1)).log(Level.INFO, anyString());
}
}
英文:
This is how I solved this issue. I refactored code a little bit:
private static final Logger LOGGER = Logger.getLogger(Context.class.getName());
public <T> T getObject(Class<T> clazz) {
T bean = null;
try {
bean = clazz.getConstructor().newInstance();
} catch (Exception e) {
LOGGER.log(Level.INFO, e, () -> "Exception occurred during Context usage whilst created " + clazz.getName());
}
return bean;
}
and here it is the test:
@Test
void getObject_ShouldThrowException() throws Exception {
Exception mockedException = mock(InstantiationException.class);
Logger mockedLogger = mock(Logger.class);
class Dummy {
public Dummy() throws Exception {
throw mockedException;
}
}
try {
Dummy dummy = context.getObject(Dummy.class);
} catch (Exception e) {
verify(mockedLogger, times(1)).log(Level.INFO, anyString());
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论