Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking slf4j with Spock

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?

like image 608
orsg Avatar asked Nov 01 '22 03:11

orsg


1 Answers

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

like image 169
Alexander Sagen Avatar answered Nov 17 '22 12:11

Alexander Sagen