Using Mockito / PowerMock to Check Log Entries

I have a class that writes messages to some magazines. A class is a utility that does nothing; it runs in the background, checks for several things, and writes them to the log. I am wondering if it is possible for me to check in the unit test that the log was written without worrying about what it actually writes. Here my class is tested:

//imports... public class MyClass { private static Log log = LogFactory.getLog(MyClass.class); public MyClass() { log.info("MyClass is being created."); } public void doThing() { if( everything_is_fine ) { log.info("This is a message to say everything is fine."); } else { log.error("Uh oh..."); } } } 

And my tester class:

 // imports ... @RunWith(PowerMockRunner.class) @PrepareForTest({MyClass.class,LogFactory.class}) public class MyClassTest { Log mockLog; @Before public void setup() { PowerMockito.mockStatic(LogFactory.class); mockLog = mock(Log.class); PowerMockito.when(LogFactory.getLog(MyClass.class)).thenReturn(mockLog); } @Test public void test_everything_is_ok() { MyClass mything = new MyClass(); // should write to log.info mything.doThing(); // should write to log.info verify(mockLog, atLeastOnce()).info(anyString()); verify(mockLog, never()).error(anyString()); } @Test public void test_everything_is_not_ok() { MyClass mything = new MyClass(); // should write to log.info // do something which makes things not ok mything.doThing(); // should write to log.error verify(mockLog, atLeastOnce()).info(anyString()); verify(mockLog, atLeastOnce()).error(anyString()); } } 

When I run the tests, I expect log.info () to be called for both tests, and log.error () to be called only for the second. However, I get "Wanted but not called" for log.info for both tests. and for log.error on the second. So either:
1) My code is broken and not logged, or
2) My test is broken.

I think I messed up something in my test, maybe something really obvious, so did anyone experience something like this that could help me? Any help would be appreciated.

UPDATE:

Thanks to those who helped, I now have a solution.

After playing a bit with the code, I found that there seems to be a problem with initializing the log. Doing private static Log log = LogFactory.getLog(MyClass.class); didn't seem to use the layout correctly, so if I translate it into the constructor, it seemed like it was taunted, and my tests all work as expected:

 public class MyClass { private static Log log; public MyClass() { MyClass.log = LogFactory.getLog(MyClass.class); log.info("MyClass is being created."); } // etc ... } 

It works for me now, but can anyone explain why the initialization of the log in the first way did not work? Or perhaps point me somewhere that explains this? I am not sure if there is a gap in my understanding of how Java initializes objects or if this is a limitation of mocking frameworks.

+4
source share
2 answers

You can abstract over Logger, as we are here in our project:

https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/LoggerProxy.groovy

Then you need to create constructors

https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/UptodatePlugin.groovy

One with initialized LoggerProxy and one for tests, where you can mock it and check if the correct text has been received. No need for dirty hacks;)

0
source

Since I had the same problem ( private static Log log = LogFactory.getLog(MyClass.class); ), I am posting what I did to solve this problem.

Instead of changing the initialization of the registrar (I was limited by the encoding rules), I just broke the test in different classes ...

0
source

Source: https://habr.com/ru/post/1490666/


All Articles