LoggerFactory 简介
单元测试常用日志打印工具LoggerFactory。
LoggerFactory
是 JUnit 平台中的一个类,用于创建Logger
实例。它被设计用于提供日志记录功能,使得 JUnit 在执行测试时能够记录信息、警告、错误等。
LoggerFactory
的主要目的是为 JUnit 提供一个集中式的日志记录机制,允许在测试过程中记录重要的信息,同时保持与不同日志实现的灵活性。这样做可以增强调试能力和监控测试执行过程中的重要事件。
package org.junit.platform.commons.logging;/*** Factory for the {@link Logger} facade for JUL.** @since 1.0*/
@API(status = INTERNAL, since = "1.0")
public final class LoggerFactory {private LoggerFactory() {/* no-op */}private static final Set<LogRecordListener> listeners = ConcurrentHashMap.newKeySet();private static final class DelegatingLogger implements Logger {}}
创建 Logger 实例(示例)
LoggerFactory
的主要职责是根据传入的参数创建适当的Logger
实例。这个实例可以用于记录不同级别的日志,例如调试信息、错误信息等。
/*** Get a {@link Logger} for the specified class.** @param clazz the class for which to get the logger; never {@code null}* @return the logger*/public static Logger getLogger(Class<?> clazz) {// NOTE: we cannot use org.junit.platform.commons.util.Preconditions here// since that would introduce a package cycle.if (clazz == null) {throw new JUnitException("Class must not be null");}return new DelegatingLogger(clazz.getName());}
调用方式:
public class Test {private Logger logger = LoggerFactory.getLogger(this.getClass());
}
使用原生的Logger有个问题就是,日志打印的时候传入的参数对象不合适,需要自己再封装,愿意如下,看Logger 接口的定义。
Logger 接口
package org.junit.platform.commons.logging;/*** The {@code Logger} API serves as a simple logging facade for* {@code java.util.logging} (JUL).** @since 1.0*/
@API(status = INTERNAL, since = "1.0")
public interface Logger {/*** Log the provided {@code Throwable} and message from the provided* {@code messageSupplier} at error level.** <p>Maps to {@link java.util.logging.Level#SEVERE} in JUL.*/void error(Throwable throwable, Supplier<String> messageSupplier);/*** Log the provided {@code Throwable} and message from the provided* {@code messageSupplier} at info level.** <p>Maps to {@link java.util.logging.Level#INFO} in JUL.*/void info(Throwable throwable, Supplier<String> messageSupplier);/*** Log the provided {@code Throwable} and message from the provided* {@code messageSupplier} at trace level.** <p>Maps to {@link java.util.logging.Level#FINER} in JUL.*/void trace(Throwable throwable, Supplier<String> messageSupplier);}
自定义Logger
因为库函数中的日志工具比较抽象,所以自定义Logger是很关键的。
一个保存数据时验证UI行为的功能。
import org.junit.platform.commons.logging.LoggerFactory;/**
* 保存数据,验证是否弹窗的功能
*/@RunWith(MockitoJUnitRunner.class)
public class TestSave {private static final String TAG = "TestSave";//内部自定义日志打印接口,没使用库的类就要自己定义接口@Mockprivate Logger logger; // Mocking the Logger class used for Log.d statements@Mockprivate SaveActivity activity;// Instance of the class to test, initialised in setUpprivate SaveActivityUnderTest saveActivityUnderTest;//过程空值变量,类似flag的作用// Helper mock boolean variables to control the test casesprivate boolean mIsShowSaveDialog;private boolean mIsApnListChanged;@Beforepublic void setUp() {saveActivityUnderTest = new SaveActivityUnderTest();saveActivityUnderTest .logger = logger;saveActivityUnderTest .activity = activity;}// Moved the class outside any other class scope to avoid issues with instantiationstatic class SaveActivityUnderTest {private Logger logger;private SaveActivity activity;public void onMenuSave() {logger.info(TAG, "MENU_SAVE: mIsShowSaveDialog = " + mIsShowSaveDialog);if (mIsShowSaveApnDialog) {if (mIsListChanged) {activity.showSaveDialog();} else {activity.finish();}} else {if (activity.validateAndSaveData()) {activity.finish();}}}}//省略测试代码//自定义接口,这是还没有实现的。private interface Logger {void d(String tag, String message);void info(String tag, String message);void error(String message);void warn(String message);}private interface SaveActivity {boolean validateAndSaveData();void showSaveDialog();void finish();}}
参考源码库定制适合自己类的log。
LoggerFactory 常量类
final class 不能被继承。
package com.demo.test.util;import org.junit.platform.commons.JUnitException;import java.util.logging.Level;
import java.util.logging.LogRecord;public final class LoggerFactory {private LoggerFactory() {/* no-op */}public static Logger getLogger(Class<?> clazz) {// NOTE: we cannot use org.junit.platform.commons.util.Preconditions here// since that would introduce a package cycle.if (clazz == null) {throw new JUnitException("Class must not be null");}return new TestLogger(clazz.getName());}private static final class TestLogger implements Logger {private static final String FQCN = TestLogger.class.getName();private final String name;private final java.util.logging.Logger julLogger;TestLogger(String name) {this.name = name;this.julLogger = java.util.logging.Logger.getLogger(this.name);}@Overridepublic void error(String tag, String message) {System.out.println(tag + ": " + message);}@Overridepublic void warn(String tag, String message) {}@Overridepublic void info(String message) {log(Level.INFO, null, message);}@Overridepublic void info(Throwable throwable, String message) {log(Level.INFO, throwable, message);}@Overridepublic void info(String tag, String message) {System.out.println(tag + ": " + message);}@Overridepublic void config(String tag, String message) {}@Overridepublic void debug(String tag, String message) {}@Overridepublic void trace(String tag, String message) {}private void log(Level level, Throwable throwable, String msg) {boolean loggable = this.julLogger.isLoggable(level);if (loggable) {LogRecord logRecord = createLogRecord(level, throwable, msg);}}private LogRecord createLogRecord(Level level, Throwable throwable, String message) {String sourceClassName = null;String sourceMethodName = null;boolean found = false;for (StackTraceElement element : new Throwable().getStackTrace()) {String className = element.getClassName();if (FQCN.equals(className)) {found = true;}else if (found) {sourceClassName = className;sourceMethodName = element.getMethodName();break;}}LogRecord logRecord = new LogRecord(level, message);logRecord.setLoggerName(this.name);logRecord.setThrown(throwable);logRecord.setSourceClassName(sourceClassName);logRecord.setSourceMethodName(sourceMethodName);logRecord.setResourceBundleName(this.julLogger.getResourceBundleName());logRecord.setResourceBundle(this.julLogger.getResourceBundle());return logRecord;}}}
Logger接口
package com.demo.test.util;public interface Logger {void error(String tag, String message);void warn(String tag, String message);void info(String message);void info(Throwable throwable, String message);void info(String tag, String message);void config(String tag, String message);void debug(String tag, String message);void trace(String tag, String message);
}