Suppress log messages during unit tests
During unit tests, it can happen that you want to suppress certain log messages to some appender. For example
- Your unit test can be about asserting that some exception takes place, which results in some log warning or error. Typically, during these kind of unit tests, you might want to temporarily suppress some logging to the console, as the warnings/errors are expected and intentional.
- Your unit tests might bootstrap a repository by extending org.onehippo.repository.testutils.RepositoryTestCase that bootstraps content of your project. However, your bootstrap content might include content that is not needed for the unit tests, and contains namespaces that are not bootstrapped by RepositoryTestCase (for example hippo:
frontend namespace)
There are two ways to suppress log messages, both having their own use cases (typically either use case 1 or 2 above). You need to have a compile dependency on hippo-repository-testutils. The ExecuteOnLogLevel is available since 2.24.00 and StringMatchFilter since 2.24.02
- Suppress log messages with org.onehippo.repository.testutils.ExecuteOnLogLevel
- Suppress log messages with org.onehippo.repository.testutils.log4j.StringMatchFilter
Suppress log messages with ExecuteOnLogLevel
When some unit test its purpose is for example to verify that some broken configuration does not break the application, or when some action results in some error that is logged but does not break the application, you can suppress the warning / error log during unit tests by wrapping some invocation that you know will result in the warn or error with ExecuteOnLogLevel.
Assume you want to assert that failing Spring configuration in addon modules does not break the HST SpringComponentManager. Your tests could be as follows:
@Test public void testFailedModuleInstances() throws Exception { final SpringComponentManager componentManager = .... ......... // assume componentManager.start() logs a warning about the wrong module componentManager.start(); assertTrue(....) componentManager.stop(); componentManager.close(); }
Now, above, the componentManager.start() logs a warning in case there a incorrect modules. The test is about the fact that incorrect modules should not fail the entire SpringComponentManager to start. Hence, the warning log is intentional and expected, thus, can be considered to be noise in the console output. Hence, suppressing the warning is cleaner. You can do this by wrapping the method (say method doI) that logs the warning with:
ExecuteOnLogLevel.xxx(new Runnable() { @Override public void run() { doIt() } }, loggerName1, loggerName2, loggerName3 .... loggerNameN);
where above the xxx can be
- debug
- info
- warn
- error
- fatal
and where loggerName1, loggerName2 ... loggerNameN is a varargs of all the loggers that should be during the doIt() invocation be temporarily set to log level xxx. The above componentManager unit test with the start() method that logs warnings can thus be rewritten as below to make sure that componentManager.start() won't log any warnings to the console : Namely, during the start() invocation, temporarily the log level is set to ERROR.
@Test public void testFailedModuleInstances() throws Exception { final SpringComponentManager componentManager = .... ......... ExecuteOnLogLevel.error(new Runnable() { @Override public void run() { componentManager.start(); } }, SpringComponentManager.class.getName()); assertTrue(....) componentManager.stop(); componentManager.close(); }
Suppress log messages with StringMatchFilter
When some unit test bootstraps a repository that results in some warnings about content bootstrapping that is not used for the unit test, it is cleaner to suppress these warnings to keep the console output during unit tests clean. In case you mock some objects, but do not mock them completely which causes some, for the unit tests, harmless warnings, it is cleaner to suppress these warnings. The StringMatchFilter is a simple org.apache.log4j.spi.Filter that can be added to a log4j appender to suppress some configurable log messages through log4j-filters.txt based on a contains criteria.
Step 1
Change the log4j.xml configuration the console appender to include the StringMatchFilter filter:
<appender name="console" class="org.apache.log4j.ConsoleAppender"> <param name="threshold" value="ERROR"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{dd.MM.yyyy HH:mm:ss} %-5p [%C.%M():%L] %m%n"/> </layout> <filter class="org.onehippo.repository.testutils.log4j.StringMatchFilter"/> </appender>
Step 2
In the same location as the log4j.xml file add a log4j-filters.txt that contains all the filters. Every line that does not start with a # is a filter. Any log message that contains the text of one of the filter lines is suppressed. For example, if the log4j-filters.txt is as follows:
# # Copyright (C) 2011 Hippo B.V. # Error initializing content for frontend-templatecomposer.xml in '/hippo:configuration/hippo:frontend/cms' Error initializing content for frontend-loader.xml in '/hippo:configuration/hippo:frontend/cms/cms-static' Error initializing content for frontend-cluster.xml in '/hippo:configuration/hippo:frontend/cms'
Then this filter means that any log message that contains in its message one of the three lines above (not the ones that start with #) is suppressed and not logged to the console appender. Thus, for example the message [Error initializing content for frontend-templatecomposer.xml in '/hippo:configuration/hippo:frontend/cms' because of unknown namespace 'hippo:frontend'] will be suppressed.