如何测试 catch (Exception e) { e.printStackTrace();} 被调用

huangapple go评论99阅读模式
英文:

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 &lt;T&gt; T getObject(Class&lt;T&gt; 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();

注意:我尚未编译和测试上述任何一种方法(而且在不同的地方,我一直将MockitoPowerMockito类名拼写错误)。


如果你坚决要在不使用库的情况下进行,你可以这样做:

  1. 创建一个自定义的Exception类型,在调用该方法时明确设置一些标志:
  2. 创建一个自定义的class,当调用无参构造函数时抛出上述的Exception
  3. 将这个自定义类的.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&lt;?&gt; 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:

  1. Create a custom Exception type, which explicitly sets some flag when that method is called:
  2. Create a custom class which throws the above Exception when the no-arg constructor is called.
  3. 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 Exceptions 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 &lt;T&gt; T getObject(Class&lt;T&gt; clazz) {
        T bean = null;

        try {
            bean = clazz.getConstructor().newInstance();
        } catch (Exception e) {
            LOGGER.log(Level.INFO, e, () -&gt; &quot;Exception occurred during Context usage whilst created &quot; + 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());
        }
    }

huangapple
  • 本文由 发表于 2020年5月5日 18:46:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/61611286.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定