How to do a JUnit assert on a message in a logger
Thanks a lot for these (surprisingly) quick and helpful answers; they put me on the right way for my solution.
The codebase were I want to use this, uses java.util.logging as its logger mechanism, and I don't feel at home enough in those codes to completely change that to log4j or to logger interfaces/facades. But based on these suggestions, I 'hacked-up' a j.u.l.handler extension and that works as a treat.
A short summary follows. Extend java.util.logging.Handler
:
class LogHandler extends Handler
{
Level lastLevel = Level.FINEST;
public Level checkLevel() {
return lastLevel;
}
public void publish(LogRecord record) {
lastLevel = record.getLevel();
}
public void close(){}
public void flush(){}
}
Obviously, you can store as much as you like/want/need from the LogRecord
, or push them all into a stack until you get an overflow.
In the preparation for the junit-test, you create a java.util.logging.Logger
and add such a new LogHandler
to it:
@Test tester() {
Logger logger = Logger.getLogger("my junit-test logger");
LogHandler handler = new LogHandler();
handler.setLevel(Level.ALL);
logger.setUseParentHandlers(false);
logger.addHandler(handler);
logger.setLevel(Level.ALL);
The call to setUseParentHandlers()
is to silence the normal handlers, so that (for this junit-test run) no unnecessary logging happens. Do whatever your code-under-test needs to use this logger, run the test and assertEquality:
libraryUnderTest.setLogger(logger);
methodUnderTest(true); // see original question.
assertEquals("Log level as expected?", Level.INFO, handler.checkLevel() );
}
(Of course, you would move large part of this work into a @Before
method and make assorted other improvements, but that would clutter this presentation.)
How can I test with junit that a warning was logged with log4j?
In the setup of the unit test:
- Get the same logger
- Make it non-additive
Add an appender which remembers the messages in a list:
public class TestAppender extends AppenderSkeleton {
public List<String> messages = new ArrayList<String>();
public void doAppend(LoggingEvent event) {
messages.add( event.getMessage().toString() );
}
}Add the appender to the logger
Now you can call your code. After the test, you will find all log messages in the list. Add the log level if you want (messages.add( event.getLevel() + " " + event.getMessage() );
).
In tearDown()
, remove the appender again and enable additivity.
How to use logger to print messages with assert
Standard assertions (i.e., assertThat()
) are meant to fail immediately with an AssertionError
.
If you would like to have custom logic in case of failures, Soft Assertions together with the callback feature might be what you are looking for.
Your example would become something like:
SoftAssertions softly = new SoftAssertions();
softly.setAfterAssertionErrorCollected(error -> logger.error("Assertion failed: {}", error));
softly.assertThat(response.statusCode())
.isEqualTo(200);
Java: using a logger in JUnit assert*
You can use a JUnit TestRule TestWatcher. A TestRule
executes code before and after the test method (similar to @Before
and @After
), but you have access to more information, and more importantly, the result of the test. A TestWatcher defines methods like succeeded()
, failed()
, starting()
and finished()
, which you can implement to get notified of events.
The following example simply prints out the failed tests with the failed assertions.
public class TestWatcherTest {
@Rule
public TestWatcher testWatcher = new TestWatcher() {
protected void failed(Throwable e, Description description) {
System.out.println("" + description.getDisplayName() + " failed " + e.getMessage());
super.failed(e, description);
}
};
@Test
public void test1() {
Assert.assertEquals("hello world", 3, 4);
}
}
You can obviously do what you like instead of the System.out.println(). This produces as output:
test1(uk.co.farwell.junit.TestWatcherTest) failed hello world expected:<3> but was:<4>
Note that a failed assertion is an exception, so you'll have access to the stacktrace etc.
How to do a JUnit assert on a message in a logger
Thanks a lot for these (surprisingly) quick and helpful answers; they put me on the right way for my solution.
The codebase were I want to use this, uses java.util.logging as its logger mechanism, and I don't feel at home enough in those codes to completely change that to log4j or to logger interfaces/facades. But based on these suggestions, I 'hacked-up' a j.u.l.handler extension and that works as a treat.
A short summary follows. Extend java.util.logging.Handler
:
class LogHandler extends Handler
{
Level lastLevel = Level.FINEST;
public Level checkLevel() {
return lastLevel;
}
public void publish(LogRecord record) {
lastLevel = record.getLevel();
}
public void close(){}
public void flush(){}
}
Obviously, you can store as much as you like/want/need from the LogRecord
, or push them all into a stack until you get an overflow.
In the preparation for the junit-test, you create a java.util.logging.Logger
and add such a new LogHandler
to it:
@Test tester() {
Logger logger = Logger.getLogger("my junit-test logger");
LogHandler handler = new LogHandler();
handler.setLevel(Level.ALL);
logger.setUseParentHandlers(false);
logger.addHandler(handler);
logger.setLevel(Level.ALL);
The call to setUseParentHandlers()
is to silence the normal handlers, so that (for this junit-test run) no unnecessary logging happens. Do whatever your code-under-test needs to use this logger, run the test and assertEquality:
libraryUnderTest.setLogger(logger);
methodUnderTest(true); // see original question.
assertEquals("Log level as expected?", Level.INFO, handler.checkLevel() );
}
(Of course, you would move large part of this work into a @Before
method and make assorted other improvements, but that would clutter this presentation.)
Related Topics
Gson - Convert from JSON to a Typed Arraylist<T>
Android/Java -- Post Simple Text to Facebook Wall
Converting a String to an Integer on Android
How to Add a Shadow and a Border on Circular Imageview Android
Retrofit2 Android: Expected Begin_Array But Was Begin_Object at Line 1 Column 2 Path $
Android.Util.Androidruntimeexception: Requestfeature() Must Be Called Before Adding Content
Background Service for Android Oreo
Why I Cant Use the Populateviewholder Override Method
Onclicklistener Not Responding
How to View My Realm File in the Realm Browser
How to Create a Bks (Bouncycastle) Format Java Keystore That Contains a Client Certificate Chain
Ionic Build Android Error When Downloading Gradle
How to Use Vectordrawable in Buttons and Textviews Using Android:Drawableright
Android - Setting a Timeout for an Asynctask
Getting Java.Net.Sockettimeoutexception: Connection Timed Out in Android
Android: How to Gain Root Access in an Android Application
How to Derive Module Descriptor: Provider {Class X} Not in Module