Tag Archives: test

Use JMockit to Unit test logging output

A very simple method of unit testing output logging is presented using a state-based mocking approach and JMockit toolkit.

Context
Java language. Logging frameworks such as Log4j, commons-logging, java.util.logging, and SLF4J. Application logs.

Introduction
Unit test logging output? Isn’t that going overboard? Most likely. However, there can be some reasons why in certain parts of a code base you’d better:

  1. Audit requirements
  2. Use of Structured Logging.
  3. Logging adheres to standards such as Common Event Expression (CEE) language. (Note, CEE has been cancelled.)
  4. Ability to maintain a system
  5. Log maintenance tools get correct data
  6. Reduce technical debt
  7. SIEM

Solution
In listing 1, a simple class uses the java.util.Logger to log. We want to make sure this class will always log this in the future, i.e., a regression test. In order to qualify as a unit test, the system under test (SUT) should be isolated. Thus, parsing an actual logging output file would not be optimal.

Listing 1

" java.util.logging.Level;
" java.util.logging.Logger;

/**  Example class that logs. */
public class Service {
	Logger logger = Logger.getLogger(this.getClass().getName());
	
	public void serve(){		
		logger.log(Level.INFO,"Hello world!");
	}
}

In listing 2 we use JMockit to mock the java.util.Logger. This should also work for other logging frameworks. JMockit has two approaches for applying mock techniques: Behavior-based and state-based.

We apply state-based below (just cause that is the one I’m starting to get the hang of). The Arrange, Act, Assert (AAA) pattern is still used, but the Assert step is in the mock object. We apply a simple ‘equals’ test. Of course, based on what we expect in the log message, a regex may be more useful.

Listing 2

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import java.util.logging.Level;
import java.util.logging.Logger;

import mockit.Mock;
import mockit.MockUp;
import mockit.Mockit;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * JUnit test for Service class.
 * @author jbetancourt
 */
public class ServiceTest {
	private Service service;

	@Before
	public void setUp() throws Exception {
		service = new Service();
	}
	
	@After
	public void tearDown() throws Exception {
		Mockit.tearDownMocks();
	}

	@Test
	public final void we_are_logging_correctly() {	
           // Arrange
           mockLogger();

           // Act
           service.serve();	
	}

	private void mockLogger() {

		new MockUp<Logger>() {
			@SuppressWarnings("unused")
			@Mock
			public void log(Level level, String msg) {
				assertThat("Hello world!", is(equalTo(msg)));
				assertThat(level, is(equalTo(Level.INFO)));
			}
		};
	}
}

Extensions
The above technique just tests that the log parameters are correct. This doesn’t check that the log output to file itself is correct. That is a different concern. Since the actual output logging is controlled by various configuration options, a unit test may not make sense. Would that be a functional test?

Of course, just checking that the message sent to the logger may not be enough. In this case a possible approach is to hook into the logging library to capture the final log output. In the java.util.logging API, one can add a new stream Handler to the Logger instance being used.

In listing 3 below a simple attempt is made to use a stream handler to capture the actual logger output used by java.util.logging.

Listing 3


public class ServiceTest{
  Logger logger = Logger.getLogger(ServiceTest.class.getName());
  private OutputStream logOut;
  private StreamHandler testLogHandler;

  @Before
  public void setUp() throws Exception {
     setUpLogHandler(logger);
  }

  /** */
  @Test
  public final void exception_log_has_all_info(){
    logger.log(Level.WARNING, "Hello world!");
    testLogHandler.flush();
    String captured = logOut.toString();
    Assert.assertTrue(captured.contains("Hello world!");
 }

 /** 
   Add stream handler to logger.  
   Will take more effort then this, e.g., may not have parent handler.
   */
  protected void setUpLogHandler(Logger logger) {
    logOut = new ByteArrayOutputStream();
    Handler[] handlers = logger.getParent().getHandlers();
    testLogHandler = new StreamHandler(logOut, handlers[0].getFormatter());
    logger.addHandler(testLogHandler);
  }
}

Software
* JUnit: 4.*
* JMockit: 0.999.11
* JDK: 1.6*
* Eclipse: IDE 1.7
* Git: 1.76.msysgit.0

Summary
Shown was a little technique that may come in handy one day. Though presented in the context of logging, it is really a simple application of state-based mock use.

Further reading


Carlos Santana/Mahavishnu John McLaughlin – The Life Divine

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

Unit Testing what will never happen?

Some developers refuse or are slow to test units for certain values or situations because, they claim, those values or situations will not occur.

Some reasons given are that the presentation tier or UI will prevent certain values; that other modules in the call chain already have error handling and validation. So why test something that won’t happen?

Let’s take an example. In the method/function below, the type will never be blank or null. Looking at the actual source code for the application will show this. So should a unit test be written that will invoke this method with a null, “”, or ” “?

public boolean service(final String type){
    // do stuff
    return result;
}

Yes!
1. Things change.
2. Bad stuff happens.
3. Development process will use invalid values.
4. More complete testing. Regression testing, path coverage, etc.
5. The method could now be used in a different call chain.
6. Its a public method, anything can invoke it, even a business partner via some remoting technology.
7. When invoked as part of other unit tests, it could have invalid values.

#3 is, I think, the most important. Did you ever do development and something not work and it turn out to be existing code that did not handle arguments correctly? That is wasted time and an aggravation. Sure, in the current production code, a blank string won’t be used, but during development, especially TDD, you scaffold code. Sometimes you don’t have values yet, so you just use a blank string.

Just the other day I tested a deployed production method that correctly tested the argument for an empty string, “”, and did the right thing. However, the code did not check for a blank string, ” “, and throws an exception. Unit testing would have shown this.

And, yes, this will never happen in our application. 🙂

Ok, you still don’t want to test something for null or invalid values? At least put this in writing in the Javadoc: “I (insert your name and address) am a great developer and stake my professional career that this method will never be invoked with invalid values.” The address is needed so us mediocre developers can hunt you down when the server crashes.

Further Reading

  1. Testing getter/setter using JUnit
  2. FindBugs and JSR-305

Off topic, some music …
If ” – Oregon (2009), from “Prime” CD.

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.