15 Junit&注解&枚举
15 Junit&注解&枚举
15.1 Junit
15.1.1 引入
【1】软件测试的目的:
软件测试的目的是在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。
【2】测试分类:
(1)黑盒测试:
软件的黑盒测试意味着测试要在软件的接口处进行。这种方法是把测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特性,只依据程序的需求规格说明书,检查程序的功能是否符合它的功能说明。因此黑盒测试又叫功能测试。
(2)白盒测试:---》Junit属于白盒测试。
软件的白盒测试是对软件的过程性细节做细致的检查。这种方法是把测试对象看做一个打开的盒子,它允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序的所有逻辑路径进行测试,通过在不同点检查程序状态,确定实际状态是否与预期的状态一致。因此白盒测试又称为结构测试。
15.1.2 没有Junit的情况下如何测试
没有使用Junit的时候,缺点:
(1)测试一定走main方法,是程序的入口,main方法的格式必须不能写错。
(2)要在同一个main方法中测试,不需要测试的东西必须注释掉。
(3)测试逻辑如果分开的话,需要定义多个测试类,麻烦。
(4)业务逻辑和测试代码,都混淆了。
代码:
package com.liweixiao.calculator;
/**
* @author:LiWeixiao
* @date:2023/2/20
* @description:
*/
public class Calculator {
//加法
public int add(int a,int b){
return a+b;
}
//减法
public int sub(int a,int b){
return a-b;
}
}
package com.liweixiao.calculator;
/**
* @author:LiWeixiao
* @date:2023/2/20
* @description:
*/
public class Test {
public static void main(String[] args) {
//测试加法
Calculator cal = new Calculator();
/*int result = cal.add(10, 20);
System.out.println(result);*/
//测试减法
int result2 = cal.sub(30, 10);
System.out.println(result2);
}
}
15.1.3 Junit的使用
【1】一般将测试和业务分离,分离为不同的包,公司域名倒着写+test
【2】测试类的名称,***Test -> 见名知义
【3】测试方法的定义,这个方法可以独立运行,不依托main方法
名字:testAdd() testSub() 见名知义
参数:无参
返回值:void
【4】测试方法定义完后,不能直接独立运行,必须在方法前加注解@Test
【5】导入Junit依赖
【6】代码
【7】判断结果:绿色,正常结果;红色,出现异常
【8】即使绿色通过,不意味测试通过。加入断言
package com.liweixiao.test;
import com.liweixiao.calculator.Calculator;
import org.junit.Assert;
import org.junit.Test;
/**
* @author:LiWeixiao
* @date:2023/2/20
* @description:
*/
public class CalculatorTest {
//测试Add加法
@Test
public void testAdd(){
System.out.println("测试Add方法");
Calculator cal = new Calculator();
int result = cal.add(10, 20);
//System.out.println(result);
//加入断言:预测结果
Assert.assertEquals(30,result);//第一个预测结果,第二个实际结果
}
//测试Sub减法
@Test
public void testSub(){
System.out.println("测试Sub方法");
Calculator cal = new Calculator();
int result = cal.sub(30, 10);
//System.out.println(result);
//加入断言
Assert.assertEquals(20,result);
}
}
15.1.4 @Before、@After
@Before
某个方法中,加入@Before注解后,这个方法的功能在测试方法执行前执行。
加入一些申请资源的代码:申请数据库资源,申请IO资源,申请网络资源...
@After
某个方法中,加入@After注解后,这个方法的功能在测试方法执行后执行。
加入一些释放资源的代码:释放数据库资源,释放IO资源,释放网络资源...
package com.liweixiao.test;
import com.liweixiao.calculator.Calculator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* @author:LiWeixiao
* @date:2023/2/20
* @description:
*/
public class CalculatorTest {
@Before
public void init(){
System.out.println("方法执行开始");
}
@After
public void close(){
System.out.println("方法执行结束");
}
//测试Add加法
@Test
public void testAdd(){
System.out.println("测试Add方法");
Calculator cal = new Calculator();
int result = cal.add(10, 20);
//System.out.println(result);
//加入断言:预测结果
Assert.assertEquals(30,result);//第一个预测结果,第二个实际结果
}
//测试Sub减法
@Test
public void testSub(){
System.out.println("测试Sub方法");
Calculator cal = new Calculator();
int result = cal.sub(30, 10);
//System.out.println(result);
//加入断言
Assert.assertEquals(20,result);
}
}
15.2 注解
15.2.1 引入
【1】历史
JDK1.5之后,注解(Annotation),也叫元数据
【2】什么是注解?
注解其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用注解,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。
使用注解时要在其前面增加@符号,并把该注解当成一个修饰符使用。用于修饰它支持的程序元素。
【3】注解的重要性:
Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的"name=value"对中。在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/ArIdroid中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。未来的开发模式都是基于注解的,JPA(java的持久化API)是基于注解的,Spring2.5以. E都是基于注解的,Hibernate3.x以后也是基于注解的,现在的Struts2有一部分也是基于注解的了,注解是一种趋势,一定程度上可以说 :框架=注解+反射+设计模式。
程序=数据结构+算法
15.2.2 注解的使用实例
Junit的注解
@Test
@Before
@After
参考上面的代码
文档相关的注解
文档注解一般使用在文档注释中,配合javadoc工具。
javadoc工具软件识别以下标签:

以上图片来自网络
package com.liweixiao.annotation;
/**
* 文档注释
* @author:LiWeixiao
* @date:2023/2/21
* @description:
* @version 1.0
*/
public class Person {
/**
* 文档注释
* 下面是eat方法,实现了XXX功能
* @param num1 就餐人数
* @param num2 点了几个菜
*/
public void eat(int num1,int num2){}
/**
*
* @param age 年龄
* @return int 返回年龄
* @exception RuntimeException 年龄大于100的异常
* @exception IndexOutOfBoundsException 年龄小于0的异常
* @see Student
*/
public int sleep(int age){
new Student();
if(age>100){
throw new RuntimeException();
}
if(age<0){
throw new IndexOutOfBoundsException();
}
return 10;
}
}
IDEA中javadoc使用,在Tools -》 Generate JavaDoc
JDK内置的3个注解
@Override:限定重写父类方法,改注解只能用于方法
package com.liweixiao.annotation02;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Student extends Person{
@Override
public void eat() {
System.out.println("子类eat方法");
}
@Deprecated
public void study(){
System.out.println("学习");
}
}
@Deprecate:用于表示所修饰元素(类、方法、构造器、属性等)已过时,通常是因为修饰的结构危险或存在更好的选择
package com.liweixiao.annotation02;
import java.util.Date;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Test {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d.getMonth());
new Student().study();
}
}
@SupperssWarnings:抑制编译器警告
package com.liweixiao.annotation02;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Test02 {
public static void main(String[] args) {
//变量未使用,显示灰色
int i;
int j=10;
@SuppressWarnings("unused")
//加上@SuppressWarnings("unused"),颜色正常,作用域下一行
//unused抑制未使用,rwatypes抑制泛型
int age=10;
int k=10;
//变量使用,颜色正常
int num=10;
System.out.println(num);
}
}
实现替代配置文件功能的注解
15.2.3 自定义注解
【1】自定义注解很少使用,一般使用现成的注解
【2】如何自定义注解:
发现定义的注解的声明使用的关键字:@interface,跟接口没有一点关系。
【3】注解的内部:
以@SuppressWarnings为例,发现内部:
这value是属性还是方法?
答案:看上去是无参数方法,实际上理解为一个成员变量,一个属性
无参数方法名字--》成员变量的名字
无参数方法的返回值--》成员变量的类型
这个参数叫 配置参数
无参数方法的类型:基本数据类型(八种),String,枚举,注解类型,还可以是以上类型对应的数组。
PS:注意:如果只有一个成员变量的话,名字尽量叫value。
【4】使用注解:
(1)使用注解的话,如果你定义了配置参数,就必须给配置参数进行赋值操作:
@MyAnnotation(value={"abc","def","hij"})
public class Person {
}
(2)如果只有一个参数,并且这个参数的名字为value的话,那么value=可以省略不写。
@MyAnnotation({"abc","def","hij"})
public class Person {
}
(3)如果你给配置参数设置默认的值了,那么使用的时候可以无需传值:
public @interface MyAnnotation2 {
String value() default "abc";
}
使用:
@MyAnnotation2
@MyAnnotation({"abc","def","hij"})
public class Person {
}
(4)一个注解的内部是可以不定义配置参数的:
public @interface MyAnnotation3 {
}
内部没有定义配置参数的注解--》可以叫做标记
内部定义配置参数的注解--》元数据
【5】注解的使用:
现在只学习注解的大致技能点,具体怎么应用 后面慢慢学习。
15.2.4 元注解
元注解是用于修饰其它注解的注解。
JDK1.5提供了四种元注解:Retention、Target、Documented、Inherited
Retention
@Retention:用于修饰注解,用于指定修饰的那个注解的生命周期,@Rentention包含一个RetentionPolicy枚举类型的成员变量,使用@Rentention时必须为该value成员变量指定值:
➢RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注释,在.class文件中不会保留注解信息
➢RetentionPolicy.CLASS:在class文件中有效(即class保留),保留在.class文件中,但是当运行Java程序时,他就不会继续加载了,不会保留在内存中,JVM不会保留注解。
如果注解没有加Retention元注解,那么相当于默认的注解就是这种状态。
➢RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),当运行 Java程序时,JVM会保留注释,加载在内存中了,那么程序可以通过反射获取该注释。
package com.liweixiao.annotation03;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
@Retention(SOURCE)
public @interface MyAnnotation3 {
}
Target
用于修饰注解的注解,用于指定被修饰的注解能用于修饰哪些程序元素。@Target也包含一个名为value的成员变量。
package com.liweixiao.annotation03;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
@Target({TYPE,FIELD,CONSTRUCTOR,METHOD})
public @interface MyAnnotation4 {
}
package com.liweixiao.annotation03;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
@MyAnnotation4
public class Student {
@MyAnnotation4
int age;
@MyAnnotation4
public Student() {
}
@MyAnnotation4
public void eat(){}
}
Documented(很少)
用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。默认情况下,javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了
Inherited(极少)
被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
15.3 枚举
15.3.1 引入
【1】
数学
枚举法:一枚一枚的列举出来。前提:有限,确定。
【2】在java类中,类的对象是有限、确定,可以定义为枚举类。
举例:星期、性别、季节
【3】自定义枚举类,JDK1.5之前
package com.liweixiao.enum01;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Season {
//属性
private final String seasonName;//季节名字
private final String seasonDesc;//季节描述
//利用构造器对属性进行赋值
//构造器私有化
private Season(String seasonName,String seasonDesc) {
this.seasonName=seasonName;
this.seasonDesc=seasonDesc;
}
//提供枚举类的有限的、确定的对象
public static final Season SPRING=new Season("春天","春暖花开");
public static final Season SUMMER=new Season("夏天","烈日炎炎");
public static final Season AUTUMN=new Season("秋天","硕果累累");
public static final Season WINNER=new Season("冬天","冰天雪地");
//额外因素
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//toString
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
package com.liweixiao.enum01;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class TestSeason {
public static void main(String[] args) {
Season summer = Season.SUMMER;
System.out.println(summer);
System.out.println(summer.getSeasonName());
}
}
15.3.2 JDK1.5之后使用enum关键字创建
JDK1.5之后,使用enum关键字创建
package com.liweixiao.enum02;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public enum Season {
//enum枚举要求对象必须放在最开始位置
//多个对象之间用英文逗号,连接,最后一个对象用英文分号;结束
SPRING("春天","春暖花开"),
SUMMER("夏天","烈日炎炎"),
AUTUMN("秋天","硕果累累"),
WINNER("冬天","冰天雪地");
//属性
private final String seasonName;//季节名字
private final String seasonDesc;//季节描述
//利用构造器对属性进行赋值
//构造器私有化
private Season(String seasonName, String seasonDesc) {
this.seasonName=seasonName;
this.seasonDesc=seasonDesc;
}
//额外因素
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
//toString
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
package com.liweixiao.enum02;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class TestSeason {
public static void main(String[] args) {
System.out.println(Season.SPRING);
System.out.println(Season.AUTUMN.getSeasonName());
//enum关键字对应的枚举类上层父类是java.lang.Enum
//自定义的枚举类的上层父类是Object
System.out.println(Season.class.getSuperclass().getName());
}
}
源码中经常看到别人定义的枚举类形态,底层没有属性、构造器、toString、get方法。
SPRING()的括号也可以省略,直接写SPRING。
package com.liweixiao.enum03;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public enum Season {
SPRING,
SUMMER,
AUTUMN,
WINNER;
}
15.3.3 Enum类的常用方法
package com.liweixiao.enum03;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class TestSeason {
public static void main(String[] args) {
//enum关键字创建的枚举类的父类是java.lang.Enum
//toString,获取对象的名字
Season autumn = Season.AUTUMN;
System.out.println(autumn);
System.out.println("------------------");
//values,返回枚举类对象的数组
Season[] values = Season.values();
for (Season s:values) {
System.out.println(s);
}
System.out.println("------------------");
//valueOf,通过对象名字获取对象
Season spring = Season.valueOf("SPRING");
System.out.println(spring);
}
}
15.3.4 枚举类实现接口
package com.liweixiao.enum04;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public interface TestInterface {
void show();
}
package com.liweixiao.enum04;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public enum Season implements TestInterface{
SPRING{
@Override
public void show() {
System.out.println("这是春天");
}
},
SUMMER{
@Override
public void show() {
System.out.println("这是夏天");
}
},
AUTUMN{
@Override
public void show() {
System.out.println("这是秋天");
}
},
WINNER{
@Override
public void show() {
System.out.println("这是冬天");
}
};
/*@Override
public void show() {
System.out.println("这是Season");
}*/
}
package com.liweixiao.enum04;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Test {
public static void main(String[] args) {
Season autumn = Season.AUTUMN;
autumn.show();
Season summer = Season.SUMMER;
summer.show();
}
}
15.3.5 实际应用
package com.liweixiao.enum05;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public enum Gender {
男,女;
}
package com.liweixiao.enum05;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Person {
//属性
private int age;//年龄
private String name;//姓名
private Gender sex;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Gender getSex() {
return sex;
}
public void setSex(Gender sex) {
this.sex = sex;
}
//方法
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
package com.liweixiao.enum05;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Test {
public static void main(String[] args) {
Person p = new Person();
p.setAge(19);
p.setName("lili");
p.setSex(Gender.女);
System.out.println(p);
}
}
还可以通过枚举结合switch处理:
package com.liweixiao.enum05;
/**
* @author:LiWeixiao
* @date:2023/2/21
* @description:
*/
public class Test02 {
public static void main(String[] args) {
Gender sex = Gender.男;
//switch可以传入枚举类型
//switch:int,short,byte,char,String,枚举
switch (sex){
case 女:
System.out.println("是个女孩");
break;
case 男:
System.out.println("是个男孩");
break;
}
}
}

浙公网安备 33010602011771号