0

I am using Mockit. I have a situation in which a method throws an exception, catches the exception and logs the exception (and without re-throwing).

Class Test {

       public void abc() {

            try {
                  xyz();
            } catch (Exception e) {
                  LOGGER.error("Exception thrown {} ", e);
            }
       } 

      private void xyz() {
         // Can throw  exception 
         // which goes to the 
         // callee   
      }
}

Now, for some scenarios xyz() can throw exception and which is caught in abc(). It is this scenario I want to test. I can't use @Test(Expected=SomeException.class) as the exception is being caught and logged. However, my test case should look if this exception thrown.

I did search online, however didn't find anything relevant.

Any pointer in how to approach would be helpful.

I referred to this SO question, which seems similar , but isn't what I am looking for.

CuriousMind
  • 8,301
  • 22
  • 65
  • 134
  • 2
    Inject a mocked logger, and verify that the mocked logger has been called: that's the only visible effect of such an exception as far as we know. – JB Nizet Dec 24 '19 at 17:05
  • @JBNizet: Can you please elaborate a bit more. I am at basic level in using Mockito. – CuriousMind Dec 24 '19 at 17:07
  • 1
    Something like `Logger mockLogger = mock(Logger.class); Test test = new Test(mockLogger); test.abc(); verify(mockLogger).error(any(), any());`. – JB Nizet Dec 24 '19 at 17:10
  • @JBNizet `...error(anyString(), any(WhateverYouLog.class));` just to add some type safety =) – Turing85 Dec 24 '19 at 17:20
  • my approach would be to unit test the method xyz() which actually throws exception. – Carlos Dec 24 '19 at 17:24
  • @JBNizet: Thanks for your suggestion. In my case, the Logger it like: private final static LOGGER = ... (in Test class). So, how will the unit test be able to set when this parameter is final and static? – CuriousMind Dec 24 '19 at 17:47
  • 1
    You'll have to refactor your code to make it testable. For example byextracting the private method to a separate class, injected into the one you have, and unit-testing this extracted method. Or by injecting a logger instead of using a private static one. – JB Nizet Dec 24 '19 at 18:34
  • @JBNizet: Can we use PowerMock for accessing private static variables? I am aware of "org.springframework.test.util.ReflectionTestUtils" , but that is helpful when we don't have static , final members. – CuriousMind Dec 24 '19 at 19:04
  • 2
    My personal view on this is that it I have to use Powermock, then it's a sign I need to refactor my code. So I don't, ever, use Powermock. – JB Nizet Dec 24 '19 at 19:25
  • @JBNizet: Thanks for your reply. Does it mean if there is need to access private members / methods (via Powermock or any other means) it is sign of refactoring code? I am still a learner of design principles, so asking this. Any pointer if you can provide would be of great learning. – CuriousMind Dec 25 '19 at 06:34

1 Answers1

1

IMO, Basically you have two options:

  1. Mock the logger (do whatever you need for this - refactoring, powermock, etc) this was already described in comments. Other than stating (based on my personal experience ) that usually usage of PowerMock is discouraged I can't really add much to it.

  2. Use a "creative" workaround: Add an artificial appender to the logger associated with the class programmatically from within the test. The appender is a "special" one that would store the logging event and will provide an access to it for verification:

// pseudo code that might vary depending on the actual logging framework of your choice
class MyTestAppender extends Appender {
     private LoggingEvent evt = null;
     public void doAppend(LoggingEvent evt) {
       this.evt = evt; 
     }
     public LoggingEvent getEvent() {
       return this.evt;
     }
}

// in test:

@Test
void test() {
    Logger logger = LoggerFactory.getLogger(ClassUnderTest.class);
    MyTestAppender myTestAppender = new MyTestAppender();
    logger.addAppender(myTestAppender);

    classUnderTest.doStuff();
    // now you can verify whether the event has been logged (and stored by the appender):

    LoggingEvent evt = myTestAppender.getEvent();
    assertNotNull(evt); // cool, something was really logged, lets see what:
    assertThat( // verify message, cause exception, whatever you want here
}
Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • Thanks for your suggestion and sample. Let me try it out if in my needs. Thanks for sharing your knowledge, and I am grateful for that. – CuriousMind Dec 25 '19 at 17:09