Tests for logging is something I have tried to avoid in the past. Today I had to write some code which exports TestRail results to splunk and I was determined to test the output.
Instead of searching for how to do this using jmockit or mockito (since this hasn't worked for me in the past) I decided to try using reflection myself. I searched for "java reflection change private static field" and came across this post on stackoverflow. The post shows a way to change the value of a public static final field. There are some caveats but in the case of Logger
it works out.
Combining this information with mockito I was able to mock the logger for a class and test logging output. First the test setup (junit 4.13):
@RunWith(MockitoJunitRunner.class)
public class SplunkReporterMethods {
@Mock private Logger log;
private SplunkReporter reporter;
@Test
public void report() {
reporter.report(new Car());
then(log).should().info("{\"name\":\"car\",\"speed\":4}");
}
}
To setup the SplunkReporter class with a different logger the mock needs to be injected into the private static final field. This can be done in an @Before
method.
@Before
void setup() {
//allow log field to be changed
Field field = SplunkReporter.class.getDeclaredField("log");
field.setAccessible(true);
//remove final modifier
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
//set to mock object
field.set(null, log);
reporter = new SplunkReporter();
}
First, the setup method makes log
accessible but that is not enough. The modifiers on the field need to be changed so final
is removed. The Field class does not have a setter for the modifiers field and so modifiers
needs to be set in field
using reflection. Finally the static field is set to the mock object.
Top comments (0)