单元测试日志打印相关接口及类 Logger

LoggerFactory 简介

单元测试常用日志打印工具LoggerFactory。

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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/5883.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

《Linux运维总结:基于银河麒麟V10+ARM64架构CPU部署redis 6.2.14 TLS/SSL哨兵集群》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:《Linux运维篇:Linux系统运维指南》 一、简介 Redis 哨兵模式是一种高可用性解决方案,它通过监控 Redis 主从架构,自动执行故障转移,从而确保服务的连续性。哨兵模式的核心组件包括哨兵(Sentine…

ENSP作业——园区网

题目 根据上图&#xff0c;可得需求为&#xff1a; 1.配置交换机上的VLAN及IP地址。 2.设置SW1为VLAN 2/3的主根桥&#xff0c;设置SW2为VLAN 20/30的主根桥&#xff0c;且两台交换机互为主备。 3.可以使用super vlan。 4.上层通过静态路由协议完成数据通信过程。 5.AR1作为企…

Navicat16 安装图文配置

Navicat是什么&#xff1f; Navicat 是一个数据库管理工具&#xff0c;它提供了一个图形界面来方便地管理和操作各种数据库。Navicat 支持多种数据库类型&#xff0c;包括 MySQL、MariaDB、SQL Server、SQLite、PostgreSQL 和 MongoDB&#xff0c;并且也支持通过 SQL 命令直接连…

模块化开发 webpack

模块化开发 & webpack 1、模块化开发 & webpack1.1 webpack 执行过程1.1.1 初始化1.1.2 编译1.1.3 输出 2.1 webpack 基础配置2.1.1 Entry2.1.1.1 context2.1.1.2 Entry类型 2.1.2 output2.1.2.1 filename2.1.2.2 publicPath2.1.2.3 path2.1.2.4 libraryTarget 和 libr…

OpenEuler 使用ffmpeg x11grab捕获屏幕流,rtsp推流,并用vlc播放

环境准备 安装x11grab(用于捕获屏幕流)和libx264(用于编码) # 基础开发环境&x11grab sudo dnf install -y \autoconf \automake \bzip2 \bzip2-devel \cmake \freetype-devel \gcc \gcc-c \git \libtool \make \mercurial \pkgconfig \zlib-devel \libX11-devel \libXext…

uni-app 图标库整合最佳实践:使用 iconfont 构建属于自己的图标库

一. 前言 在前端开发中&#xff0c;图标已经成为页面设计中不可或缺的一部分。图标可以使界面更加美观、清晰&#xff0c;并且能够提升用户体验。而使用图标库来管理和引用图标资源&#xff0c;可以带来更多的便利和效率。 而在众多的图标库中&#xff0c;iconfont 独树一帜。…

刷题强训 (day1) -- 数字统计

1、数字统计 1.1题目 1.2 思路 根据题目得知我们要统计2出现的次数&#xff0c;那么这就是一个枚举 数字拆分的过程&#xff0c;先设一个变量count统计2出现的次数&#xff0c;那么count怎么变化呢&#xff1f; 当然了出现一个2&#xff0c;count就1&#xff0c;重点在于如何…

AI-基本概念-向量、矩阵、张量

1 需求 需求&#xff1a;Tensor、NumPy 区别 需求&#xff1a;向量、矩阵、张量 区别 2 接口 3 示例 4 参考资料 【PyTorch】PyTorch基础知识——张量_pytorch张量-CSDN博客

Halcon区域分割之分水岭分割法

现实中我们见到过有山有湖的景象&#xff0c;那么一定是水绕山、山围水的情形。当然可在需要的时候人工构筑分水岭&#xff0c;以防集水盆之间的互相穿透。而区分高山与水的界线以及湖与湖之间的间隔&#xff0c;就是分水岭。 分水岭分割法是一种基于拓扑理论的数学形态…

数据结构与算法——图

图 1.图的定义和表示 图的定义 图G由集合V和集合E组成&#xff0c;记作G(V,E),其中&#xff1a; 1、V是顶点元素的有限集合&#xff1b; 2、E是顶点间关系——边的有限集合。 3、边是顶点的无序对或有序对。 无向图和有向图&#xff1a; 无向图 由没有方向的边构成的图…

FebHost:法国.FR域名的市场前景和挑战

.FR域名的未来前景如何&#xff1f; .fr域名在2023年经历了显著增长&#xff0c;新注册量大幅增加。这一积极趋势凸显了法国 VSE&#xff08;极小型企业&#xff09;和 SME&#xff08;中小型企业&#xff09;数字化转型的持久影响&#xff0c;这一转变早在 2022 年就已开始。…

SQL进阶技巧:如何计算复合增长率?

目录 0 场景描述 1 数据准备 2 问题分析 3 小结 0 场景描述 复合增长率是第N期的数据除以第一期的基准数据&#xff0c;然后开N-1次方再减去1得到的结果。假如2018年的产品销售额为10000&#xff0c;2019年的产品销售额为12500&#xff0c;2020年的产品销售额为15000&…

开源的 API 学习平台「GitHub 热点速览」

前有 5 万颗星标的开源项目 HTTPie 因误操作导致 Star 清零&#xff08;2022 年&#xff09;&#xff0c;上周知名开源项目 Elasticsearch 也经历了 Star 一夜清零的事件。这些事故的原因均是管理员误将开源项目从公开状态转为私有状态所导致。为避免类似事件再次发生&#xff…

华为HD集群重启NAMENODE实例操作步骤

华为HD集群重启NAMENODE实例操作步骤 管理员账号进入FI——服务——HDFS&#xff0c;选择角色&#xff1a;namenode重启namenode&#xff08;备&#xff09; 如下图&#xff1a;点击【实例】–角色选择【Namenode】–选择备节点&#xff08;自己记录一下当前备节点的IP&…

LoRA:大型语言模型(LLMs)的低秩适应;低秩调整、矩阵的低秩与高秩

目录 LoRA:大型语言模型(LLMs)的低秩适应 一、LoRA的基本原理 二、LoRA的举例说明 三、LoRA的优势 低秩调整、矩阵的低秩与高秩 一、低秩调整(LoRA) 二、矩阵的低秩 三、矩阵的高秩 LoRA:大型语言模型(LLMs)的低秩适应 LoRA(Low-Rank Adaptation of LLMs),…

CST参数扫描设置细节

cst参数扫描的细节 点开参数扫描对话框&#xff0c;新建扫描参数&#xff0c; 例如参数a进行扫描1-2&#xff0c;0.5的步长&#xff0c;这样最后会出现3个参数的仿真结果。 这时如果增加参数b的扫描&#xff0c;在同一sequence下&#xff0c;同样1-2&#xff0c;0.5的步长&…

最高降本90%!它究竟是如何实现的?

第一、云在未来“优先”&#xff0c;病毒攻击和人为错误将成主要威胁 根据Gartner预测&#xff0c;到2025年&#xff0c;超过95%的新数字工作负载将被部署在云原生平台上&#xff0c;超过85%的企业机构将接受云优先原则。 在这一背景下&#xff0c;勒索病毒攻击和人为错误成为…

OpenCV—calcHist()函数

void calcHist( const Mat* images, int nimages,const int* channels, InputArray mask,SparseMat& hist, int dims,const int* histSize, const float** ranges,bool uniform true, bool accumulate false ); images 输入的数据指针&#xff0c;要具备相同的尺寸和数…

用例怎么链接到其他地方的序列图

龙勤思(2018年1月22日)&#xff1a; 潘老师&#xff0c;你在PPT里说分析序列图的位置在用例下面。但是你上课时给的EA模板里需求和分析是分成两个包的&#xff0c;所以分析序列图没办法直接加为系统用例的下级元素 潘加宇: 这页幻灯片有点老了&#xff0c;回头我更新。严格来…

Java | Leetcode Java题解之第540题有序数组中的单一元素

题目&#xff1a; 题解&#xff1a; class Solution {public int singleNonDuplicate(int[] nums) {int low 0, high nums.length - 1;while (low < high) {int mid (high - low) / 2 low;mid - mid & 1;if (nums[mid] nums[mid 1]) {low mid 2;} else {high …