0

I have a class that looks like this:

class Service {
    private final Logger lgr = LoggerFactory.getLogger(Service.class);

    public void doService() {
        lgr.info("Do Service");
    }
}

public class Controller {
    private final Logger lgr = LoggerFactory.getLogger(Controller.class);

    @Autowired
    private Service service;

    protected void doSomething() {
        //do something
        lgr.info("LOG something"); // lgr line
        // do something else

    }
}

And the corresponding test class that looks like this:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ControllerTest.class, LoggerFactory.class})
public class ControllerTest {
    private Controller controller;

    @Mock
    private Service service;

    @Before
    public void init() {
        controller = Mockito.mock(Controller.class, Mockito.CALLS_REAL_METHODS);
    }

    @Test
    public void testDoSomething() {
        controller.doSomething();  // calling doSomething method of Controller class
        // some other statements
    }
}

Here, when the call goes to doSomething() method, at line lgr line, the lgr object is null, due to which my unit test is failing with NullPointerException.

Can someone please, help me fix this?

user97
  • 67
  • 6
  • Make it static and do this: https://stackoverflow.com/questions/8948916/mocking-logger-and-loggerfactory-with-powermock-and-mockito – Tom Cools Apr 14 '20 at 15:04
  • I know that after making the logger static, I can use mockstatic etc., but the existing class already has a on static logger class, so I prefer to not change it. – user97 Apr 14 '20 at 15:08
  • Ok, but then why are you trying to add another logger? Seems a bit strange to me. – Tom Cools Apr 14 '20 at 15:18
  • I'm not trying to add any logger, there's an existing class which has a non static logger, and a non static method which logs something with this logger object. I'm trying to write a UT to test something in this method, but that's giving a NPE, as the lgr object in that method is null. – user97 Apr 14 '20 at 15:27
  • Are you trying to test if the logger is called? Or are you testing the controller.doSomething()? if it's the latter, don't mock it but create a new instance: @Before public void init() { controller = new Controller() } – Tom Cools Apr 14 '20 at 15:31
  • I'm mocking it, as there're a lot of autowired fields in the Controller class, which I thought would be hard to inject without adding @Mock fields. – user97 Apr 14 '20 at 15:34
  • You never Mock the class you are testing, you only mock the dependencies. :-) For future questions: Please share the entire class (you only shared a part, which made it difficult to see what you wanted to do). If you update this question with your full class, i'll have a look at it. – Tom Cools Apr 14 '20 at 15:36
  • Thanks for adding. For what you want to do, you don't actually need PowerMock :-). Here is what you should change: - Don't put autowired on a field. Create a constructor where you pass in the Service and (optionally) put Autowired on the constructor. - in your test Before, create a new controller and pass the Mocked Service into the constructor. Before public void init() { controller = new Controller(service); } – Tom Cools Apr 14 '20 at 15:54
  • Thank you, but is there any way, I can programatically inject mock Service object into mock Controller object? – user97 Apr 14 '20 at 16:01
  • 1
    Through the Constructor, or by using MockitoAnnoations.initMocks() (see https://stackoverflow.com/questions/32263208/why-cant-i-use-injectmocks-field-matching-when-running-with-powermockrunner) – Tom Cools Apr 14 '20 at 16:05

0 Answers0