6

I have a Groovy class annotated with @Slf4j, so it gets a private final Logger log field, whose usage I'd like to test. I want to continue using @Slf4j and not expose the log field any further just to enable testing.

I'm writing my tests using Spock 1.0 and tried to accomplish this using Spock's integration mocking and stubbing functionality. Global stubbing should help me intercept the LoggerFactory invocation to get the actual Logger instance, so my current guess is this:

LoggerFactory logFactory = GroovyStub(global: true)
logFactory.getLogger(_) >> Mock(Logger)
// create my @Slf4j-annotated object afterwards

Interestingly, the interception actually works, println confirms that the class actually gets an object Mock for type 'Logger' named 'dummy', but the second statement that instructs the stub to return a mock does not seem to catch. Instead the default stub behaviour returns yet another stub, that cannot be used for mocking of course:

org.spockframework.runtime.InvalidSpecException: Stub 'dummy' matches the following required interaction:

1 * plugin.log.warn(_)   (0 invocations)

Remove the cardinality (e.g. '1 *'), or turn the stub into a mock.

What do I need to change to let the stubbed LoggerFactory return a mock Logger?

orsg
  • 631
  • 1
  • 6
  • 15
  • For people not using `@slf4j`, this questions may be useful http://stackoverflow.com/q/24439151/239408 – xverges Nov 19 '15 at 17:06

3 Answers3

3

You need to set the private final log-field with reflection, as explained here: Unit testing of a class with StaticLoggerBinder

Community
  • 1
  • 1
Alexander Sagen
  • 3,998
  • 1
  • 17
  • 15
0

If you want to test the log output, why don't you let the logging framework do their work and test the outcome (a log file)? You would only need to wire the log output to a file that you access after the test has run.

This could possibly result in less brittle tests.

Luis Muñiz
  • 4,267
  • 1
  • 24
  • 40
  • How do I do this? I tried to use http://projects.lidalia.org.uk/slf4j-test/ but my classpath already contains an slf4j backend, so I cannot change this (and don't want to change it for all my tests). – orsg May 22 '15 at 08:37
0

You can use a slf4j test backend to assert logging behavior like spf4j-slf4j-test. Slf4j will pick up the first backend implementation in your classpath, which is why you need to have the test backend dependency listed first in your project dependencies. (in the test scope).

user2179737
  • 453
  • 3
  • 6