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;
        }
    }
}
posted @ 2023-02-20 17:00  LiWeixiao  阅读(30)  评论(0)    收藏  举报