0

In my code I have a try-finally method.I don't want finally block for my unit testing.Can I mock the entire finally block in my class,because in my case it is just logging ?I am using PowerMockito for my unit testing.

try {
    String foo = obj.myMethod();
} finally {
    logger.info(obj.webService());
}
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
Miller
  • 744
  • 3
  • 15
  • 39
  • Why is logging an issue when you're testing ? – Nir Alfasi Jun 20 '17 at 16:24
  • 1
    Why do you want to mock a block. You can only mock objects not blocks or loops. – kk. Jun 20 '17 at 16:25
  • 3
    Why not just mock the logger? – Oliver Charlesworth Jun 20 '17 at 16:25
  • @alfasin because i am getting null pointer exception,while calling my webservices and i dont want any value from my webservices during my return. – Miller Jun 20 '17 at 16:26
  • 1
    You should inject a mock `obj` and potentially create an expectation for `obj.webService()`. In production, the code will call `obj.webService()`, and so in your testing you should too. – slim Jun 20 '17 at 16:29
  • I mocked the value for foo. – Miller Jun 20 '17 at 16:30
  • Assuming that `obj` is injected (because I know you follow good practice) you can use Mockito's: `when(obj.webService()).thenReturns("")` with a mocked `obj` and you're golden. – Nir Alfasi Jun 20 '17 at 16:32
  • Put whatever in your finally block in a method and mock that. But, yeah, as others have alluded, this practice is rather pointless. – jingx Jun 20 '17 at 16:32
  • @alfasin logger present in finally is giving me warning and nullpointer exception.Can I suppress it? – Miller Jun 20 '17 at 16:33
  • I don't like the approach of suppressing exceptions, but you can do: https://stackoverflow.com/a/156528/1057429 That said, it will be a better practice to follow Slim's advice in his answer below! – Nir Alfasi Jun 20 '17 at 16:41

2 Answers2

2

The class you have written will invoke logger.info(obj.webService()) and therefore your tests should exercise that.

It is not a good idea to make your class-under-test do something different depending on whether it's being run in a test or not. All you can change is its collaborators, often by replacing them with mocks.

In this case obj is the collaborator. So inject a mock of obj. Depending on the intent of your test, it may be enough to use the default, so the logger will log null, or you might need to specify a when to make obj.webService() return a valid object, or you might even want to verify that it was called.

slim
  • 40,215
  • 13
  • 94
  • 127
  • I'm making an assumption, but the assumption is that the NPE is that the logger iteslf is null. Properly mocking the main collaborator foo is great, but does not address the 2nd collaborator, logger. – Kevin Welker Jun 20 '17 at 16:50
0

In the comments you state that you want to avoid calling your webservices during test.

i dont want any value from my webservices during my return.

I would argue you also don't want this if the log level setting of your application is set to WARNING or higher. (I'm assuming java default logging here)

The solution is then simple : use the logging form which takes a Supplier : Logger.info(Supplier<String> msgSupplier)

So your finally block would become :

} finally {
    logger.info(() -> obj.webService());
}

Then, for your tests, or in production for that matter, it's simply a case of setting your logging to Level.NONE, and the supplier will never be executed.

bowmore
  • 10,842
  • 1
  • 35
  • 43