Rob Williams is a probabilistic Lean coder of Java and Objective-C. Rob is a DZone MVB and is not an employee of DZone and has posted 170 posts at DZone. You can read more from them at their website. View Full User Profile

Setting Logger Levels in Tests, Using an ITD

12.14.2009
| 4564 views |
  • submit to reddit

Long time ago, I wrote a class called LoggerLevelStack. The idea is simple: make it possible to set a logger level programmatically from inside a test, then when the test is over, have the prior level restored automatically. The problem with it in use was that you had to make an instance, then remember to call revertAll() in the teardown(). The ITD removes these hassles: it injects the instance into the test class, and injects an @After method that reverts the levels.

package com.ontometrics.util;

import org.junit.After;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Level;

import com.ontometrics.util.test.LoggerLevelStack;

public aspect LoggerLevelStackInjector {

private static Logger log = LoggerFactory.getLogger(LoggerLevelStackInjector.class);

private LoggerLevelStack Tester.loggerLevelStack = new LoggerLevelStack();

public void Tester.setLevel(Class logClass, Level level){
this.loggerLevelStack.setLevel(logClass, level);
}

public void Tester.setLevel(String packagePattern, Level level){
this.loggerLevelStack.setLevel(packagePattern, level);
}

@After
public void Tester.testLoggerTearDown(){
log.info("teardown called");
this.loggerLevelStack.revertAll();
}

declare parents: (com.ontometrics..*Test) implements Tester;


}

Since we are dealing with tests here, the joinpoint expression is simple: any class that ends with the name Test.

Usage is simple: test classes show that they are being intercepted by the aspect, and it's possible to just call this.setLevel(..), like so:

@Before
public void setup() throws SecurityException, NoSuchFieldException {

this.setLevel(Space.class, Level.DEBUG);
this.setLevel(CompoundCase.class, Level.DEBUG);

}

Aspects are good.

From http://www.jroller.com/robwilliams

 

2
Your rating: None Average: 2 (1 vote)
Published at DZone with permission of Rob Williams, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Josh Marotti replied on Mon, 2009/12/14 - 2:39pm

What's wrong with having a log config for just the test that you load in the test?  That's what I do when I run my unit tests.  It loads a test log4j config that routes all debug information to the console.  My main app loads a production config file that is separate.

 

But if you insist on using it the way you state:

Aspects are good, but this is an instance where you are doing something that any other developer may not be aware of.  I would think a better way to work around this is to have a parent test that sets up and tears down for you, and your tests just inherit from it.

And if all else fails, you can create your own test runner to use to do the same thing.

 

The difference between the aspect approach and the two approaches I've made is with the two approaches I've made, you know what is happening (there is a parent class or custom test runner) and don't override teardown without checking.  With aspects, everything looks normal, but changes (adding in a log file or teardown that does something funky) can cause the test to fall over and it can be difficult to find the problem.

 

 It's not that I'm against aspects, I just think they should do things 'extra' that don't impact the code they run very much (ie: timing/performance checking, trace logging, etc...)

 

Hope that all makes sense...

Mladen Girazovski replied on Mon, 2009/12/14 - 3:27pm

I can't think of any good reason why i would want to have my (automated & self checking) unittests write logs, unless its just a debug output, and for that purpose System.out is perfect for temporary logging.

I think the authors was about to test his logging system, not have his unittests write logs ;)

Quando Hauerler replied on Tue, 2009/12/15 - 1:47am

@mgira:

Sure, the unit-test itself may not need logging (but sometimes this is veeerrry helpful).

But what, if there's a problem aka failure in your (other-non-unit-test-)code?

Maybe "your code" is capable of providing "good" log-messages which might track down this problem?
It's only convenient to turn on logging then, look what's printed, fix the error, run again, turn logging off.

The alternative is starting up a debugger, isn't it?

I think, the approach of fortknox ("having different log-configuration") is the better one for this scenario, since you can change log-levels without changing code.
With Robs approach, you need to edit code, compile (the whole project cause of aspect) and rerun (of course only when one wants to CHANGE the levels).

(BTW: "Testing the logging system" with logging turned off is somewhat strange, isn't it? Except you want to test, that nothing is printed at all. But then there should be a special unit-test for this...)

Mladen Girazovski replied on Tue, 2009/12/15 - 3:54am in response to: Quando Hauerler

 Sure, the unit-test itself may not need logging (but sometimes this is veeerrry helpful).

If its not needed it for the test, it's not supposed to be in the test.

In my unittest code i sometimes use System.out temporarly if i need some output, afterwards i delete it again. 

But what, if there's a problem aka failure in your (other-non-unit-test-)code?

Maybe "your code" is capable of providing "good" log-messages which might track down this problem?
It's only convenient to turn on logging then, look what's printed, fix the error, run again, turn logging off.

I use Maven2, so i can have different log configurations for test and non-test.

The alternative is starting up a debugger, isn't it? 

 Only if i am really desperate ;)

I use the debugger rarely, if at all.

I think, the approach of fortknox ("having different log-configuration") is the better one for this scenario, since you can change log-levels without changing code.
With Robs approach, you need to edit code, compile (the whole project cause of aspect) and rerun (of course only when one wants to CHANGE the levels).

(BTW: "Testing the logging system" with logging turned off is somewhat strange, isn't it? Except you want to test, that nothing is printed at all. But then there should be a special unit-test for this...)

I think i understood the authors intention now better thanks to your explonation.

So, yes, it is a vaid way of configuring the logging system from the tests, which is ok if there isn't another convinient way for doing so.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.