tags:

views:

800

answers:

3

Hi,

I've repeatedly had problems with the DSL introduced by Grails in version 1.1 for configuring Log4J. My current configuration looks like this:

log4j = {        
    debug 'com.mypackages'

    appenders {
        console name: 'stdout', layout: pattern(conversionPattern: '%d{dd-MM-yyyy HH:mm:ss,SSS} %5p %c{1} - %m%n')
        rollingFile name: 'hibeFile', file: "hibeFile", maxFileSize: '500KB'
    }

    // By default, messages are logged at the error level to both the console and hibeFile
    root {
        error 'stdout', 'hibeFile'
        additivity = true
    }
}

The intention here is:

  • Log com.mypackages at the debug level and all others at the error level
  • Log all output to a file named hibeFile and the console

This works fine when I run the application or the integration tests. However, when I run the unit tests no logging appears either in the console, or in the "System.out" or "System.err" links shown in the Grails test report. How can I see my logs when running unit tests?

Thanks, Don

+1  A: 

AFAIK, when running a Grails unit test, the whole logging is not available via log4j, the log.xxxx calls in domain classes etc. are just mocked using

mockLogging(ClassUnderTest, true)

The "true" stands for "enable debug". In order to do so, the unit test class must extend GrailsUnitTestCase. If you use mockController(class), it implicitly calls mockLogging(class, false) and therefore you get no debug logging. For details check out the grails sources, esp GrailsUnitTestCase and MockUtils.

In opposite to the above, in an integration test the whole machinery is started and log4j is available.

Stefan
so how do you test a controller that is littered with logging statements? I have this problem now??
Aaron Saunders
use mockLogging(MyDamnCoolCOntroller, true) in your test's setUp() method.
Stefan
+1  A: 

Here is a thought, you didn't ask this exactly but the same question was asked on the grails user group. I am posting my answer here as well, to spread the knowledge.

If you are explicitly saying def log = org.apache.commons.logging.LogFactory.getLog(this) in your classes rather than relying on dependency injection as was explained on the grails user group you can mock the getLog on the LogFactory.

The below is taken from grails.tests.MockUtils.mockLogging and modified to return the logger.

class LoggingEnabledTestCase extends GrailsUnitTestCase {
protected void setUp() {
        super.setUp()
        registerMetaClass(org.apache.commons.logging.LogFactory)
        org.apache.commons.logging.LogFactory.metaClass.'static'.getLog = {instance ->

            // This is taken from grails.tests.MockUtils and slightly changed to return a logger.

            // Get the name of the class + the last component of the package
            // (if it the class is in a package).
            def pos = instance.class.name.lastIndexOf('.')
            if (pos != -1) pos = instance.class.name.lastIndexOf('.', pos - 1)
            def shortName = instance.class.name.substring(pos + 1)

            // Dynamically inject a mock logger that simply prints the
            // log message (and optional exception) to stdout.
            def mockLogger = [
                    fatal: {String msg, Throwable t = null ->
                        println "FATAL (${shortName}): $msg"
                        if (t) {
                            println "       Exception thrown - ${t.message}"
                        }
                    },
                    error: {String msg, Throwable t = null ->
                        println "ERROR (${shortName}): $msg"
                        if (t) {
                            println "       Exception thrown - ${t.message}"
                        }
                    },
                    warn: {String msg, Throwable t = null ->
                        println "WARN (${shortName}):  $msg"
                        if (t) {
                            println "       Exception thrown - ${t.message}"
                        }
                    },
                    info: {String msg, Throwable t = null ->
                        println "INFO (${shortName}):  $msg"
                        if (t) {
                            println "       Exception thrown - ${t.message}"
                        }
                    },
                    debug: {String msg, Throwable t = null ->
                        println "DEBUG (${shortName}): $msg"
                        if (t) {
                            println "       Exception thrown - ${t.message}"
                        }
                    },
                    trace: {String msg, Throwable t = null -> },
                    isFatalEnabled: {-> true},
                    isErrorEnabled: {-> true},
                    isWarnEnabled: {-> true},
                    isInfoEnabled: {-> true},
                    isDebugEnabled: {-> true},
                    isTraceEnabled: {-> false}] as Log
            return mockLogger
        }
    }

    protected void tearDown() {
        super.tearDown()
    }
}
Tiggerizzy
A: 

Using Grails 1.1.1 and an approximation to your setup, I have a unit test called FooTests.groovy

After running grails test-app, I am able to see the output from the test in the directory:

./test/reports/plain

specifically in the files, as appropriate:

TEST-com.mypackages.FooTests-err.txt
TEST-com.mypackages.FooTests-out.txt
TEST-com.mypackages.FooTests.txt

Note that I see no output in the hibeFile. I'm not sure, but I suspect a previous poster is correct in that unit tests don't receive the logging setup.

Michael Easter