1、单元测试
1.1 概述【理解】
JUnit是一个 Java 编程语言的单元测试工具。JUnit 是一个非常重要的测试工具
1.2 特点【理解】
- JUnit是一个开放源代码的测试工具。
- 提供注解来识别测试方法。
- JUnit测试可以让你编写代码更快,并能提高质量。
- JUnit优雅简洁。没那么复杂,花费时间较少。
JUnit在一个条中显示进度。如果运行良好则是绿色;如果运行失败,则变成红色。
1.3 使用步骤【应用】
注意,zip文件需要解压得到jar包
使用步骤
- 将junit的jar包导入到工程中 junit-4.9.jar(不会添加点击jar包详解)
- 编写测试方法该测试方法必须是公共的无参数无返回值的非静态方法
- 在测试方法上使用@Test注解标注该方法是一个测试方法
- 选中测试方法右键通过junit运行该方法
代码示例
public class JunitDemo1 {
@Test
public void add() {
System.out.println(2 / 0);
int a = 10;
int b = 20;
int sum = a + b;
System.out.println(sum);
}
}
1.4 相关注解【应用】
注解说明 | 注解 | 含义 | | —- | —- | | @Test | 表示测试该方法 | | @Before | 在测试的方法前运行 | | @After | 在测试的方法后运行 |
代码示例
public class JunitDemo2 {
@Before
public void before() {
// 在执行测试代码之前执行,一般用于初始化操作
System.out.println("before");
}
@Test
public void test() {
// 要执行的测试代码
System.out.println("test");
}
@After
public void after() {
// 在执行测试代码之后执行,一般用于释放资源
System.out.println("after");
}
}
2、日志技术
2.1 概述
- 概述
程序中的日志可以用来记录程序在运行的时候点点滴滴。并可以进行永久存储。 - 日志与输出语句的区别
| | 输出语句 | 日志技术 | | —- | —- | —- | | 取消日志 | 需要修改代码,灵活性比较差 | 不需要修改代码,灵活性比较好 | | 输出位置 | 只能是控制台 | 可以将日志信息写入到文件或者数据库中 | | 多线程 | 和业务代码处于一个线程中 | 多线程方式记录日志,不影响业务代码的性能 |
2.2 体系结构
2.2.1 Apache基金会
Apache软件基金会(也就是Apache Software Foundation,简称为ASF),为支持开源软件项目而办的一个非盈利性组织。
2.2.2 Log4J
Log4j是Apache的一个开源项目。
通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件等位置。
我们也可以控制每一条日志的输出格式。
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
2.2.3 Logback的介绍
Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch。它当前分为下面几个模块:
- logback-core:其它两个模块的基础模块
- logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging
- logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能
2.3 Logback取代log4j的理由
1、更快的实现:Logback的内核重写了,在一些关键执行路径上性能提升10倍以上。而且logback不仅性能提升了,初始化内存加载也更小了。 2、非常充分的测试:Logback经过了几年,数不清小时的测试。Logback的测试完全不同级别的。 3、Logback-classic非常自然实现了SLF4j:Logback-classic实现了SLF4j。在使用SLF4j中,你都感觉不到logback-classic。而且因为logback-classic非常自然地实现了slf4j , 所以切换到log4j或者其他,非常容易,只需要提供成另一个jar包就OK,根本不需要去动那些通过SLF4JAPI实现的代码。 4、非常充分的文档 官方网站有两百多页的文档。 5、Logback的定制性更加灵活,同时也是spring boot的内置日志框架 6、自动重新加载配置文件,当配置文件修改了,Logback-classic能自动重新加载配置文件。扫描过程快且安全,它并不需要另外创建一个扫描线程。这个技术充分保证了应用程序能跑得很欢在JEE环境里面。 等等很多~~
2.4 Logback 的配置介绍
1、Logger、appender及layout
- Logger(记录器)作为日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。
- Appender(附加器)主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、PostreSQL、 Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等。
- Layout(布局) 负责把事件转换成字符串,格式化的日志信息的输出。
2、logger context
各个logger 都被关联到一个 LoggerContext,LoggerContext负责制造logger,也负责以树结构排列各logger。其他所有logger也通过org.slf4j.LoggerFactory 类的静态方法getLogger取得。 getLogger方法以 logger名称为参数。用同一名字调用LoggerFactory.getLogger 方法所得到的永远都是同一个logger对象的引用。
3、有效级别及级别的继承
Logger 可以被分配级别。级别包括:TRACE、DEBUG、INFO、WARN 和 ERROR,定义于ch.qos.logback.classic.Level类。如果 logger没有被分配级别,那么它将从有被分配级别的最近的祖先那里继承级别。root logger 默认级别是 DEBUG。
4、打印方法与基本的选择规则
打印方法决定记录请求的级别。
例如,如果 L 是一个 logger 实例,那么,语句 L.info(“..”)是一条级别为 INFO的记录语句。记录请求的级别在高于或等于其 logger 的有效级别时被称为被启用,否则,称为被禁用。
记录请求级别为 p,其 logger的有效级别为 q,只有则当 p>=q时,该请求才会被执行。该规则是 logback 的核心。日志级别为: TRACE < DEBUG < INFO < WARN < ERROR
2.5 Logback的 默认配置
- 如果配置文件
logback-test.xml
和logback.xml
都不存在,那么 logback 默认地会调用BasicConfigurator ,创建一个最小化配置。最小化配置由一个关联到根 logger 的ConsoleAppender 组成。 输出用模式为
**%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n **
的 PatternLayoutEncoder 进行格式化。root logger 默认级别是 DEBUG。Logback的配置文件 Logback 配置文件的语法非常灵活。
- 正因为灵活,所以无法用 DTD 或 XML schema 进行定义。
- 尽管如此,可以这样描述配置文件的基本结构:以
开头,后面有零个或多个 元素,有零个或多个 元素,有最多一个 元素。
Logback默认配置的步骤
- 尝试在 classpath下查找文件logback-test.xml;
- 如果文件不存在,则查找文件logback.xml;
- 如果两个文件都不存在,logback用BasicConfigurator自动对自己进行配置,这会导致记录输出到控制台。
2.6 logback.xml 常用配置详解
- logback.xml配置文件的基本结构可以描述为
元素
包含零个或多个
后跟零个或多个
后跟最多一个
下图说明了这种基本结构:
logback日志系统详解.pdf
2.7 logback.xml 配置示例
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 在此未说明属性为非必须的,那就表示属性必须设置 -->
<!-- *****************最小配置文件结构介绍******************************* -->
<!--
<configuration>
<appender></appender> //存在1或多个,功能指定记录输出目的地
<root></root> //最多存在一个,根logger
<logger><logger> //存在1或多个,普通logger
</configuration>
-->
<!-- *************************各个标签详细介绍********************************** -->
<!--
configuration属性
debug(非必须)属性:true表示输出logback内部的日志信息(不影响配置和级别) ;
scan(非必须)属性:默认为false,true表示扫描配置文件的变化并自动重新配置,默认每隔1分钟扫描一次;
scanPeriod(非必须)属性:搭配scan属性使用,设置扫描的间隔时间
-->
<configuration debug="true" scan="true" scanPeriod="1 seconds">
<!-- 用于指定logger上下文名称,默认为default -->
<contextName>logback</contextName>
<!--
设置变量FILE_PATH,用于指定名为FILE的appender的目的文件存放的目录
定义日志文件的存储地址, 勿在 LogBack 的配置中使用相对路径
-->
<property name="FILE_PATH" value="D:/"></property>
<!-- **********************配置TurboFilter类型的过滤器**********************************
TurboFilter类型过滤器有三种:这里使用的是DuplicateMessageFilter
子标签<cacheSize>:表示内部缓存对旧消息引用的个数上限
子标签<allowedRepetitions>:表示允许消息出现的重复次数上限,超过次数上限的记录请求将被丢弃
-->
<!-- 使用自定义的TurboFilter -->
<turboFilter class="logback.SampleTurboFilter">
</turboFilter>
<!-- 使用DuplicateTurboFilter -->
<turboFilter class="ch.qos.logback.classic.turbo.DuplicateMessageFilter">
<allowedRepetitions>1</allowedRepetitions>
<cacheSize>20</cacheSize>
</turboFilter>
<!-- ************************常用的Appender************************************** -->
<!--
<appender>标签包含2个属性:name、class
name属性:指定appender名称;class属性:指定目的地类型 (比如ConsoleAppender、FileAppender等)
class属性的值决定了<appender>标签包含的子标签的种类。
-->
<!-- 控制台日志, 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--
encoder:将事件转换为字符串,默认配置为PatternLayoutEncoder类
encoder用于替代Layout,encoder扩展了Layout功能
Layout功能:只负责把事件转换为字符串,但是不能指定何时将记录写入到指定目的地
encoder功能:即负责把事件转换为字符串,也可以指定何时将记录写入到指定目的地
-->
<encoder>
<!-- 指定输出格式
%d{} :表示时间
%thread:请求记录所在的线程名
%-5level:用5位显示请求级别
%logger{36}:输出logger名,{36}表示logger名最大占用的字符位数,{0}表示最简短logger名(不包含包名)。
-->
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} -%msg%n</pattern>
</encoder>
</appender>
<!-- 该appender的功能是将记录信息以特定格式写到文件 -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!-- $使用变量FILE_PATH的格式,类似Linux中使用的格式:${FILE_PATH} -->
<file>${FILE_PATH}/file.log</file>
<encoder>
<!-- 指定输出格式 -->
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} -%msg%n</pattern>
</encoder>
</appender>
<!-- ***********************以最小窗体为指定的滚动规则的appender*****************************
RollingFileAppender类型的appender中必须包含4个子标签:<file>、<rollingPolicy>、<triggerPolicy>、<encoder>
<rollingPolicy>标签用于指定滚动规则,该标签有一个属性class:用于指定实现具体的滚动规则的类。
<triggerPolicy>标签用于指定发生滚动的条件,该标签有一个属性class:用于指定具体滚动条件的类。
<rollingPolicy>和<triggerPolicy>中具体包含哪些子标签是由class属性指定的类来决定的,因为不同的类有不同的参数,从而需要不同的标签来传参
-->
<!-- 该appender的功能是将记录信息以特定格式写到文件,当文件达到20MB时,创建以特定规则新的文件,之后的记录会写到新文件-->
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 在第一次触发滚动之前记录将会写到该文件中 -->
<file>${FILE_PATH}/rolling.log</file>
<!--
前提条件:class的值为FixedWindowRollingPolicy,表示以最小窗体为指定的滚动规则
RollingPolicy标签必须子标签:<fileNamePattern>、<minIndex>、<maxIndex>
<fileNamePattern>:表示滚动条件达到后,创建文件名的规则,其中"%i"代表数字1~5。第一次触发条件,创建文件rolling1.log,并且记录开始写到这个文件中
<minIndex>与<maxIndex>共同决定了文件的个数
-->
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<!--日志文件输出的文件名-->
<fileNamePattern>${FILE_PATH}/rolling%i.log</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>5</maxIndex>
</rollingPolicy>
<!--
<triggeringPolicy>功能:用于限制文件大小
前提条件:class的值为SizeBasedTriggeringPolicy,表示以文件大小为触发条件
只有一个子标签<maxFileSize>用于指定触发条件
-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<!--日志文件最大的大小-->
<maxFileSize>20MB</maxFileSize>
</triggeringPolicy>
<!--格式化输出-->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} -%msg%n</pattern>
</encoder>
</appender>
<!-- *****************************根据时间滚动 为滚动规则和条件的appender(最常用)***********************-->
<!--
该appender的功能:将记录信息以特定格式写到文件,当文件达到20MB时,创建以时间为特定规则新的 文件,之后的记录会写到新文件,
文件个数最多维持10个,文件达到10个 后删除旧的文件
-->
<appender name="time_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- TimeBasedRollingPolicy实现了RollingPolicy与TriggeringPolicy,
因此只需要<rollingPolicy>标签,不需要<TriggeringPolicy>标签
<rollingPolicy>标签有两个子标签:<fileNamePattern>、<maxHistory>
<fileNamePattern>:用于指定文件名命名规则
<maxHistory>:保留文件的个数,超过了就删除创建时间最久的文件
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 文件名 -->
<fileNamePattern>${FILE_PATH}/java_log/test%d{yyyy-MM-dd_HH-mm}.log</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} -%msg%n</pattern>
</encoder>
</appender>
<!-- ***********************常规级别过滤器的使用****************************************
本配置功能:过滤并接受请求级别为debug的请求,对于其他级别请求一律丢弃。
-->
<appender name="level_console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} -%msg%n</pattern>
</encoder>
</appender>
<!-- ***********************常规临界值滤器的使用****************************************
本配置功能:请求级别高于或等于info的请求响应NEUTRAL(进入下一个环节),低于info的级别请求响应DENY(表示丢弃)。
-->
<appender name="threshold_console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} -%msg%n</pattern>
</encoder>
</appender>
<!-- appender的目的地为mysql数据库 -->
<appender name="jdbc" class="ch.qos.logback.classic.db.DBAppender">
<!-- 这里只使用jdbc中的DriverManager获得连接,不使用任何数据源 -->
<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://localhost:3306/logback?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC</url>
<user>root</user>
<password>root</password>
</connectionSource>
</appender>
<!-- ******以下DBAppender类型的appender的目的地为mysql数据库******** -->
<appender name="c3p0_datasource" class="ch.qos.logback.classic.db.DBAppender">
<!-- 这里使用DataSource获得连接-->
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<!-- 实现DataSource的数据库连接池有很多,比如DBCP、c3p0、Druid等,这里使用的是c3p0
-->
<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
<user>root</user>
<password>root</password>
<driverClass>com.mysql.jdbc.Driver</driverClass>
<jdbcUrl>jdbc:mysql://localhost:3306/logback?useUnicode=true&characterEncoding=utf8</jdbcUrl>
</dataSource>
</connectionSource>
</appender>
<appender name="Druid_datasource" class="ch.qos.logback.classic.db.DBAppender">
<!-- 这里使用DataSource获得连接-->
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<!-- 实现DataSource的数据库连接池有很多,比如DBCP、c3p0、Druid等,这里使用的是Druid-->
<dataSource class="com.alibaba.druid.pool.DruidDataSource">
<username>root</username>
<password>root</password>
<driverClassName>com.mysql.jdbc.Driver</driverClassName>
<url>jdbc:mysql://localhost:3306/logback?useUnicode=true&characterEncoding=utf8</url>
</dataSource>
</connectionSource>
</appender>
<appender name="dbcp_datasource" class="ch.qos.logback.classic.db.DBAppender">
<!-- 这里使用DataSource获得连接-->
<connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">
<!-- 实现DataSource的数据库连接池有很多,比如DBCP、c3p0、Druid等,这里使用的是dbcp-->
<dataSource class="org.apache.commons.dbcp.BasicDataSource">
<username>root</username>
<password>root</password>
<driverClassName>com.mysql.jdbc.Driver</driverClassName>
<url>jdbc:mysql://localhost:3306/logback?useUnicode=true&characterEncoding=utf8</url>
</dataSource>
</connectionSource>
</appender>
<!-- level属性:指定根logger的分配级别 -->
<root level="debug">
<!-- ref属性:指定根logger关联的appender -->
<appender-ref ref="STDOUT"></appender-ref>
</root>
<!-- name:指定logger名称;level:指定logger的分配级别;additivity(非必须,默认为true):设置appender叠加性 -->
<!-- show parameters for hibernate sql 专为 Hibernate 定制 -->
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
<logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
<logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />
<!--myibatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<logger name="demo" level="debug" additivity="false">
<appender-ref ref="FILE"/>
</logger>
<logger name="demo2" level="debug">
<appender-ref ref="rollingFile"/>
</logger>
<logger name="demo3" level="debug">
<appender-ref ref="time_file"/>
</logger>
<logger name="demo4" level="debug" additivity="false">
<appender-ref ref="level_console"/>
</logger>
<logger name="demo5" level="debug" additivity="false">
<appender-ref ref="threshold_console"/>
</logger>
<logger name="demo6" level="debug" additivity="false">
<appender-ref ref="jdbc"/>
</logger>
<logger name="demo7" level="debug" additivity="false">
<appender-ref ref="c3p0_datasource"/>
</logger>
<logger name="demo8" level="debug" additivity="false">
<appender-ref ref="Druid_datasource"/>
</logger>
<logger name="demo9" level="debug" additivity="false">
<appender-ref ref="dbcp_datasource"/>
</logger>
</configuration>
2.8 logback.xml 入门案例【应用】
- 点击此处可下载xmllogback.xml
- 点击此处可下载jar包日志jar包.zip ```xml <?xml version=”1.0” encoding=”UTF-8” ?>
<!-- ************************常用的Appender************************************** -->
<!--
<appender>标签包含2个属性:name、class
name属性:指定appender名称;class属性:指定目的地类型 (比如ConsoleAppender、FileAppender等)
class属性的值决定了<appender>标签包含的子标签的种类。
-->
<!--
本appender的功能是将记录信息以特定格式写到控制台
CONSOLE : 表示当前日志信息是可以输送到控制台的。
-->
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<!--encoder:将事件转换为字符串
默认配置为PatternLayoutEncoder类
encoder用于替代Layout,encoder扩展了Layout功能
Layout功能:只负责把事件转换为字符串,但是不能指定何时将记录写入到指定目的地
encoder功能:即负责把事件转换为字符串,也可以指定何时将记录写入到指定目的地
-->
<encoder>
<!-- 指定输出格式
%d{} :表示时间
%thread:请求记录所在的线程名
%-5level:用5位显示请求级别
%logger{36}:输出logger名,{36}表示logger名最大占用的字符位数,{0}表示最简短logger名(不包含包名)。
%msg 日志文本
%n换行
-->
<pattern>[%level] %blue(%d{HH:mm:ss.SSS}) %cyan([%thread]) %boldGreen(%logger{15}) -%msg %n</pattern>
</encoder>
</appender>
<!--
name:指定logger名称;
level:指定logger的分配级别;
additivity(非必须,默认为true):
设置appender叠加性 -->
<!--root设置全局的log level-->
<root name="com.lhl" level="DEBUG" additivity="false">
<appender-ref ref="Console" />
</root>
- 使用步骤
- ① 导入logback的相关jar包
- 在模块下新建lib文件夹与src同级
- 将jar包复制进lib文件夹下
- 添加到依赖库中,`Add as library`
- 
- ② 编写logback配置文件
- ③ 在代码中获取日志的对象
- ④ 按照级别设置记录日志信息
- 代码示例
```java
// 测试类
public class Test01 {
//获取日志的对象
private static final Logger LOGGER = LoggerFactory.getLogger(Test01.class);
public static void main(String[] args) {
//1.导入jar包
//2.编写配置文件
//3.在代码中获取日志的对象
//4.按照日志级别设置日志信息
LOGGER.debug("debug级别的日志");
LOGGER.info("info级别的日志");
LOGGER.warn("warn级别的日志");
LOGGER.error("error级别的日志");
}
}
运行测试文件