I have a class with SLF4J logger instanced like:
public class MyClass {
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
public void foo() {
log.warn("My warn");
}
}
And I need to test it with JMockit like:
@Test
public void shouldLogWarn(@Mocked Logger log) throws Exception {
new Expectations() {{
log.warn(anyString);
}};
MyClass my = new MyClass();
my.foo();
}
After searching a lot I figured out, I need to use MockUp somehow. But can't get it how exactly.
Btw, I'm using last version of JMockit(1.29) where you no more can setField(log) for final static fields.
@Capturing
annotation that works for this situationIndicates a mock field or a mock parameter for which all classes extending/implementing the mocked type will also get mocked.
Future instances of a capturing mocked type (ie, instances created sometime later during the test) will become associated with the mock field/parameter. When recording or verifying expectations on the mock field/parameter, these associated instances are regarded as equivalent to the original mocked instance created for the mock field/parameter.
This means that if you annotate it with @Capturing
instead of @Mocked
, every Logger
that is created during the test run will be associated with one you annotated. So the following works:
@Test
public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
// This really ought to be a Verifications block instead
new Expectations() {{
logger.warn(anyString);
}};
MyClass my = new MyClass();
my.foo();
}
As a side note, if all you want to do is verify that a method is called, it's better to use Verifications instead, since that is what it is intended for. So your code would look like this:
@Test
public void shouldLogWarn(@Capturing final Logger logger) throws Exception {
MyClass my = new MyClass();
my.foo();
new Verifications() {{
logger.warn(anyString);
}};
}
@Mocked
on both Logger
and LoggerFactory
In some cases, @Capturing
won't work as intended due to intricacies of how the annotation works. Fortunately, you can also get the same effect by using @Mocked
on both Logger
and LoggerFactory
like so:
@Test
public void shouldLogWarn(@Mocked final LoggerFactory loggerFactory, @Mocked final Logger logger) throws Exception {
MyClass my = new MyClass();
my.foo();
new Verifications() {{
logger.warn(anyString);
}};
}
Note: JMockit 1.34 through 1.38 has a bug that prevents this from working with slf4j-log4j12
, and possibly other dependencies of SLF4J. Upgrade to 1.39 or later if you run into this bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With