1

I need some help on logging and unit testing. The class under test is a Zk GenericForwardComposer and i want to exclude concrete logging and logging configuration from the test. Im following a kind of TDD and have a test failure because of logging. Ive posted the class under test and the test. My test doesnt have any configuration for log4j because I want as pure a unit test as possible and as simple as possible.


The test failure:

log4j:ERROR setFile(null,true) call failed.
    java.io.FileNotFoundException: /log/t2-console.log (No such file or directory)
    at java.io.FileOutputStream.open(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:136)
    at org.apache.log4j.FileAppender.setFile(FileAppender.java:294)
    at org.apache.log4j.RollingFileAppender.setFile(RollingFileAppender.java:207)
    at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:165)
    at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:307)
    at org.apache.log4j.xml.DOMConfigurator.parseAppender(DOMConfigurator.java:295)
    at org.apache.log4j.xml.DOMConfigurator.findAppenderByName(DOMConfigurator.java:176)
    at org. apache.log4j.xml.DOMConfigurator.findAppenderByReference(DOMConfigurator.java:191)
    at org.apache.log4j.xml.DOMConfigurator.parseChildrenOfLoggerElement(DOMConfigurator.java:523)
    at org.apache.log4j.xml.DOMConfigurator.parseCategory(DOMConfigurator.java:436)
    at org.apache.log4j.xml.DOMConfigurator.parse(DOMConfigurator.java:1004)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:872)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:778)
    at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:526)
    at org.apache.log4j.LogManager.<clinit>(LogManager.java:127)
    at org.apache.log4j.Logger.getLogger(Logger.java:117)
    at com.t2.integration.controller.IntegrationSearchController.<clinit>(IntegrationSearchController.java:60)
    at com.t2.integration.controller.IntegrationSearchControllerTest.doesSomeCalling(IntegrationSearchControllerTest.java:14)


I haven't configured the unit test for Log4j and I want to follow Red-Green-Refactor. I think I could handle the logging call in the test but want to find a way to exclude logging entirely if that's possible.

public class IntegrationSearchControllerTest {

    @Test
    public void doesSomeCalling() {
        IntegrationSearchController searchController = new IntegrationSearchController();
    }
}

I don't want any ZK context or ZK integration testing components to leak into my unit tests. And I want the tests to be as simple as possible. Is it AOP, interfaces, dependency injection or refactoring?

The class under test:

package ...

import org.apache.log4j.Logger;

public class IntegrationSearchController extends IntegrationBaseController {

   private static final Logger LOGGER = Logger.getLogger(IntegrationSearchController.class);
...

The controller is ZK managed

Crowie
  • 3,220
  • 7
  • 28
  • 48
  • [this](http://stackoverflow.com/a/878559/977087) answer about adding Log4J configuration to `/src/test/resources` might end up being the alternative – Crowie Aug 14 '13 at 19:20
  • I've been given advice to sorting out logging for a unit test before on [this](http://stackoverflow.com/q/17113235/977087) question. In the question above I don't want my test to be impacted by concrete logging at all. In the meantime I will have to use one of the alternative solutions. – Crowie Aug 14 '13 at 19:59

1 Answers1

2

As your Logger is static (normal) you will need to use a mock framework that can mock statics. This is much more difficult to do (from a framework perspective as it usually involves manipulating byte code). Anyway it's been done and you have options.

Here's how it would look using PowerMock with Mockito:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Logger.class)
public class TestIntegrationSearchController {

    @Before
    public void initMockLogger() {
        mockStatic(Logger.class);
        when(Logger.getLogger(any(Class.class))).thenReturn(mock(Logger.class));
    }

    @Test
    public void test() {
        IntegrationSearchController controller = new IntegrationSearchController();
        // controller.LOGGER is a Mockito mocked Logger
    }

}

Note: you don't need to set up mocking in an @Before but I find it reads easier.

Now.. all that said, I think you're solving the wrong problem here. Rather than mocking logging in every test, consider alternatives that obviate the need. For example, you could use a different Log4J configuration in tests which logs to STDOUT.

Community
  • 1
  • 1
Sean Connolly
  • 5,692
  • 7
  • 37
  • 74
  • Yeah I reckon that's the first point you made to my ZK controller testing and I see what you mean now. cheers man ya helped me figure out the new question to ask. Good answer dude – Crowie Aug 28 '13 at 13:52