深入理解Java(七)—— 日志技术和单元测试

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断 问题的追踪以及理解系统的活动等重要作用;而单元测试则是指对软件中的最小可测试单元进行检查和验证。在本文中,我们会详细谈论目前市面上主流的日志技术和单元测试框架。

7 日志技术和单元测试

作者:来自ArimaMisaki创作

[TOC]

7.1 日志技术

7.1.1 基本概念

程序中的日志:程序中的日志可以用来记录程序运行过程的信息。

输入信息的转变方式

  • 传统记录日志:使用输出语句观察程序运行的过程
  • 如今记录日志:使用API查看日志

输出语句的弊端

  • 信息只能展示在控制台
  • 不能将其记录到其他位置
  • 想取消记录的信息需要修改代码才可以完成

记录日志的优势

  • 可以被定向到不同的处理器,用于在控制台显示,用于存储在文件中等。
  • 可以随时以开关的形式控制是否记录日志,无需修改源代码。
  • 可以采用不同的方式格式化,如纯文本或XML。
  • 可以对记录进行过滤。过滤器可以根据过滤实现器指定的标准丢弃那些无用的记录项。


7.1.2 日志技术体系结构

日志规范:一些接口,提供给日志的实现框架设计的标准。

日志框架:绝活哥或者第三方公司已经做好的日志记录实现代码,后人可直接使用。

两种日志规范

  • 官方日志规范接口Commons Logging,简称JCL
  • 第三方日志接口Simple Logging Facade for Java,简称slf4j

日志实现框架

  • Log4j
  • JUL
  • Logback
  • 其他实现


7.1.3 Logback的用法

说明:由log4j的创始人设计的一个开源日志组件,性能比log4j要好。其基于slf4j的日志规范实现的框架

官网日志返回首页 (qos.ch)

Logback技术模块

  • logback-core:logback-core模块为其他两个模块奠定了基础,必须要有
  • logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j的API
  • logback-acccess:模块与Tamcat和Jetty等Servlet容器集成,以提供HTTP访问日志功能

Logback的初步使用

  • 在项目新建文件夹lib,导入Logback的相关jar包到该文件夹下,并添加到项目依赖库中去。
  • 将Logback的核心配置文件logback.xml直接拷贝到src目录下。
  • 在代码中获取日志的对象。
public static final Logger LOGGER = LoggerFactory.getLogger("类对象");

附-logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。
     默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="60 seconds" debug="true">

    <!-- 定义变量,可通过 ${log.path}和${CONSOLE_LOG_PATTERN} 得到变量值 -->
    <property name="log.path" value="D:/log" />
    <property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} |-[%-5p] in %logger.%M[line-%L] -%m%n"/>

    <!-- 输出到控制台 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!-- Threshold=即最低日志级别,此appender输出大于等于对应级别的日志
             (当然还要满足root中定义的最低级别)
        -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <!-- 日志格式(引用变量) -->
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- 追加到文件中 -->
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <file>${log.path}/hello2.log</file>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- 滚动追加到文件中 -->
    <appender name="file2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/hello.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录
             文件超过最大尺寸后,会新建文件,然后新的日志文件中继续写入
             如果日期变更,也会新建文件,然后在新的日志文件中写入当天日志
        -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 新建文件后,原日志改名为如下  %i=文件序号,从0开始 -->
            <fileNamePattern>${log.path}/hello-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 每个日志文件的最大体量 -->
            <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>8kb</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 日志文件保留天数,1=则只保留昨天的归档日志文件 ,不设置则保留所有日志-->
            <maxHistory>1</maxHistory>
        </rollingPolicy>
    </appender>

    <root level="trace">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="file"/>
        <appender-ref ref="file2"/>
    </root>

</configuration>

基本使用

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo {
    //创建日志对象
    public static Logger LOGGER = LoggerFactory.getLogger("Demo.class");
    public static void main(String[] args) {
        try {
            LOGGER.debug("main方法开始执行了");
            LOGGER.info("我开始记录第二行日志,我们开始做除法");
            int a = 10;
            int b = 0;
            LOGGER.trace("a = "+a);
            LOGGER.trace("b="+b);

            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("功能出现异常"+e);
        }
    }
}


7.1.4 Logback的配置

说明:Logback日志系统的特性都是通过核心配置文件logback.xml控制的

配置说明

标签 说明
\<append> 设置输出位置和日志信息的详细格式
\<target> 设置日志颜色
\<file> 设置日志输出路径
\<maxFileSize> 指定单个日志文件的大小,一旦溢出则生成新日志文件
\<fileNamePattern> 指定拆分的日志集中放置的位置
\<pattern> 使用正则匹配来完全提示信息,其中%d表示日期,%thread表示线程名,%-nlevel表示级别从左显示n个字符宽度,%c表示类名,%msg表示日志信息

输出到配置台的配置标志

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

输出到系统文件的配置标志

<appender name="file2" class="ch.qos.logback.core.rolling.RollingFileAppender">

关联日志输出内容

    <root level="trace">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="file"/>
        <appender-ref ref="file2"/>
    </root>

日志级别设置

  • 日志级别程度依次为:TRACE<DEBUG<INFO<WARN<ERROR,默认级别是debug。对应日志对象中的方法名。
  • 日志级别作用:用于控制系统中哪些日志级别是可以输出的,只输出级别不低于设定级别的日志信息。
  • ALL和OFF分别是打开和关闭全部日志信息。

日志等级修改:只需修改level的值即可。

    <root level="trace">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="file"/>
        <appender-ref ref="file2"/>
    </root>


7.2 单元测试

说明:单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性。

在之前的学习中,如果我们要测试一个方法,都是采用是个main方法,里面包含多个方法来测试,但这样做会导致问题:如果中间一个方法失效,则下面的方法测试也会受到影响。


7.2.1 Junit单元测试框架

说明

  • Junit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当学习并使用Junit编写单元测试。
  • 此外,几乎所有的IDE工具都继承了Junit。我们可以直接在IDE中编写并运行Junit测试,Junit目前最新的版本是5。

优点

  • Junit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。
  • Junit可以生成全部方法的测试报告。
  • 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。


7.2.2 单元测试的快速入门

步骤讲解

  1. 将Junit的jar包导入到项目中,如果你在联网的情况下,可以先写Test注解后按alt+回车让其自动导入。
  2. 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法。
  3. 在测试方法上使用@Test注解:标注该方法是一个测试方法。
  4. 在测试方法中完成被测试方法的预期正确性测试。
  5. 选中测试方法,选择Junit运行,如果测试良好是绿色,如果失败则为红色。

image-20220725190942653

局部测试和总体测试:如果我们在测试类中任意空白位置右键Run,则会测试所有方法;如果我们在测试类中的方法上右键Run,则会测试单个方法。

public class UserService {
    public String loginName(String loginName,String passWord){
        if("admin".equals(loginName) && "123456".equals(passWord)) return "登录成功";
        else return "用户名或者密码有问题";
    }

    public void selectNames(){
        System.out.println(18/0);
        System.out.println("查询全部用户名称成功");
    }
}
import org.junit.Assert;
import org.junit.Test;

/**测试类*/
public class TestUserService {
    @Test
    public void testLoginName(){
        UserService userService = new UserService();
        String rs = userService.loginName("admin","123456");
        Assert.assertEquals("您的功能业务数据可能出BUG","登录成功",rs);
    }

    @Test
    public void testSelectNames(){
        UserService userService = new UserService();
        userService.selectNames();
    }
}


7.2.3 Junit常用注解

Junit4.x注解:开始执行的方法常用于初始化资源;执行完之后的方法常用于释放资源。

注解 说明
@Test 测试方法
@Before 用来修饰实例方法,该方法会在每个测试方法执行之前执行一次
@After 用来修饰实例方法,该方法会在每个测试方法执行之后执行一次
@BeforeClass 用来修饰静态方法,该方法会在所有测试方法执行之前执行一次
@AfterClass 用来修饰静态方法,该方法会在所有测试方法执行之后执行一次

Junit5.x注解

注解 说明
@Test 测试方法
@BeforeEach 用来修饰实例方法,该方法会在每个测试方法执行之前执行一次
@AfterEach 用来修饰实例方法,该方法会在每个测试方法执行之后执行一次
@BeforeAll 用来修饰静态方法,该方法会在所有测试方法执行之前执行一次
@AfterAll 用来修饰静态方法,该方法会在所有测试方法执行之后执行一次


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
16天前
|
前端开发 JavaScript 测试技术
前端测试技术中,如何提高集成测试的效率?
前端测试技术中,如何提高集成测试的效率?
|
2月前
|
Java Shell
「sh脚步模版自取」测试线排查的三个脚本:启动、停止、重启、日志保存
「sh脚步模版自取」测试线排查的三个脚本:启动、停止、重启、日志保存
39 1
|
2月前
|
存储 运维 监控
Elasticsearch Serverless 高性价比智能日志分析关键技术解读
本文解析了Elasticsearch Serverless在智能日志分析领域的关键技术、优势及应用价值。
Elasticsearch Serverless 高性价比智能日志分析关键技术解读
|
16天前
|
数据采集 前端开发 安全
前端测试技术
前端测试是确保前端应用程序质量和性能的重要环节,涵盖了多种技术和方法
|
2月前
|
存储 监控 网络协议
服务器压力测试是一种评估系统在极端条件下的表现和稳定性的技术
【10月更文挑战第11天】服务器压力测试是一种评估系统在极端条件下的表现和稳定性的技术
120 32
|
23天前
|
前端开发 JavaScript 测试技术
前端小白逆袭之路:如何快速掌握前端测试技术,确保代码质量无忧!
【10月更文挑战第30天】前端开发技术迭代迅速,新手如何快速掌握前端测试以确保代码质量?本文将介绍前端测试的基础知识,包括单元测试、集成测试和端到端测试,以及常用的测试工具如Jest、Mocha、Cypress等。通过实践和学习,你也能成为前端测试高手。
39 4
|
2月前
|
Java 程序员 应用服务中间件
「测试线排查的一些经验-中篇」&& 调试日志实战
「测试线排查的一些经验-中篇」&& 调试日志实战
23 1
「测试线排查的一些经验-中篇」&& 调试日志实战
|
28天前
|
编解码 安全 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(10-2):保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali——Liinux-Debian:就怕你学成黑客啦!)作者——LJS
保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali以及常见的报错及对应解决方案、常用Kali功能简便化以及详解如何具体实现
|
2月前
|
人工智能 Oracle Java
解决 Java 打印日志吞异常堆栈的问题
前几天有同学找我查一个空指针问题,Java 打印日志时,异常堆栈信息被吞了,导致定位不到出问题的地方。
36 2
|
2月前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
25 3