NullPointer
NullPointer

Reputation: 1024

unit tests and logging

I have a couple of classes: StateProcessor and State. I want to write a test for the method StateProcessor.process(State). The logic of this method is pretty simple, but it contains a lot of logging messages.

logger.info(state.getSourse().toString());
if (state.getTarget() == Target.A) {
 logger.info(state.getCreationTime());
 service.doSmth(state);
} else {
 logger.info(state.getTagret().getName());
 service.doOtherStff(state);
}

I don't want to pass the real State instance to the process method because this class is really complicated and it takes a lot of lines of code to build it. So, I want to pass mock object created with Mockito. According to the main logic, I need to mock only getTarget() method. But the execution will fail with NPE at state.getTagret().getName() and at state.getSourse().toString(). But I don't like the idea of mocking all of these methods! They used only for logging. Also I don't want to fix my tests every time when I add some logging messages.

Logging is really useful there, so I don't want to remove it at all. But mocking the methods only for logging looks strange.

How I can solve this issue?

Upvotes: 0

Views: 239

Answers (3)

Ryan Nelson
Ryan Nelson

Reputation: 4666

What you have there is a classic Law of Demeter violation, which is a textbook case for mocking problems.

As an alternative, consider logging the entire State object in one place--such as before the 'if' block--and overriding the toString() method to output everything you need to see. Then you won't need to dereference each field and mock each method.

Upvotes: 1

John B
John B

Reputation: 32949

Consider Mocking DEEP. This will result in each method call returning a mock instead of null and prevent the NPEs.

 Foo mock = mock(Foo.class, RETURNS_DEEP_STUBS);

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 691635

You could enclose all your logging calls inside an if (!test) {} block and inject the test attribute.

Or you could enclose them into an if (logger.isInfoEnabled()) {} block and configure logging with info disabled, or inject a mock logger which returns false for isInfoEnabled().

But logging is a key part of your code. So if you really want to test that it won't blow up in production, you should either test for nulls in your production code, or prove that these attributes may never return null, and inject a mock which doesn't return null either.

PS: do you really intend to keep properties named tagret and sourse in your code?

Upvotes: 0

Related Questions