stefanbirkner / system-rules

A collection of JUnit rules for testing code which uses java.lang.System.
http://stefanbirkner.github.io/system-rules
Other
546 stars 71 forks source link

System.err calls not intercepted when working with java.util.logging.* component #40

Closed santoshgokak closed 8 years ago

santoshgokak commented 8 years ago

The default Logger uses the java.util.logging.ConsoleHandler which publishes log records to System.err. I wrote the below test to validate that i can read the System.err logs from System rules but they are not being captured.

import org.junit.Rule
import org.junit.Test
import org.junit.contrib.java.lang.system.SystemErrRule

import java.util.logging.Logger

import static org.junit.Assert.assertEquals

public class SampleTest {
  //Logger
  private final static Logger LOGGER = Logger.getLogger(SampleTest.class.getName());

  @Rule
  public final SystemErrRule systemErrRule = new SystemErrRule().enableLog();

  @Test
  public void writesTextToSystemErr() {
    LOGGER.info("hello world");
    assertEquals("hello world", systemErrRule.getLog());
  }
}

The above fails with

org.junit.ComparisonFailure: expected:<[hello world]> but was:<[]>
    at org.junit.Assert.assertEquals(Assert.java:115)
    at org.junit.Assert.assertEquals(Assert.java:144)
    at org.junit.Assert$assertEquals.callStatic(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:53)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:157)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:169)

Is there any extra step/configuration required? I am running my tests from gradle.

stefanbirkner commented 8 years ago

The problem is that java.util.logging.ConsoleHandler stores a reference to System.err internally. System Rules cannot modify this reference to the real System.err. I suggest to implement a specific handler for testing logging:

import org.junit.Rule
import org.junit.Test
import org.junit.contrib.java.lang.system.SystemErrRule

import java.util.logging.Logger

import static org.junit.Assert.assertEquals

public class SampleTest {
  //Logger
  private final static Logger LOGGER = Logger.getLogger(SampleTest.class.getName());

  @Test
  public void logsText() {
    TestHandler handler = new TestHandler();
    LOGGER.info("hello world");
    logger.addHandler(handler)
    try {
      assertEquals("hello world", handler.message);
    } finally {
      LOGGER.removeHandler(handler);
    }
  }

  private static class TestHandler extends Handler {
    String message;

    @Override
    public void publish(LogRecord record) {
      message = record.getMessage();
    }

    @Override
    public void flush() {
    }

    @Override
    public void close() throws SecurityException {
    }
  }
}

This would make a nice rule, too.