菜鸟笔记
提升您的技术认知

java之单元测试与注解与枚举

软件测试

目的:在规定的条件下,对程序进行操作,以发现程序错误,衡量软件质量,并对其是否满足设计要求进行评估的过程

测试分类

黑盒测试:软件的黑盒测试意味着测试要在软件的接口处进行,这种方法是把测试对象看作一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特性,只依据程序的需求规格说明书,检查程序的功能是否符合功能说明。因此,黑盒测试又称功能测试

白盒测试:软件的白盒测试是对软件的过程细节做细致的检查。这种方法是把测试对象看作一个打开的盒子,它允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序的所有逻辑路径进行测试,通过在不同点检查程序状态,确定实际状态是否与预期的状态一致。因此,白盒测试又称结构测试。

junit测试(白盒测试)

没有junit测试时的缺陷

  • 测试一定要走main方法,是程序的入口,main方法的格式必须不能写错
  • 要是在同一个main方法中测试的话,那么不需要测试的东西必须注释掉
  • 测试逻辑如果分开的话,需要定义多个测试类,麻烦
  • 业务逻辑和测试代码都混淆了

关于测试

  • 一般测试和业务分离,分离为不同的包,名字建议为:公司域名倒写+test,以后的测试类都放在这个包下
  • 测试类的名字要见名知意
  • 测试类可以独立运行,不依托于main方法
  • 测试方法参数为无参,返回值为void
  • 测试方法定义完后不能独立运行,必须要在方法前加注解@Test并导入junit环境
  • 判定结果(绿色:正常;红色:异常)
  • 即使出现绿色效果,也不意味着测试通过,因为代码中可能出现问题,解决方法:加入断言

断言

语法:Assert.assertEquals(期望结果,实际结果);

作用:当期望结果与实际结果不符,那么就抛出异常 

    @Test
    public void testOut(){
        System.out.println("测试开启");
        //0,1的随机数
        long round = Math.round(Math.random());
        //加入断言,若真实值不等于期望值则抛出异常
        //第一个参数:预测结果    第二个参数:实际结果
        Assert.assertEquals(1, round);
    }

@Before与@After

@Before:某一测试方法中若加入了@Before注解以后,那么此方法中的功能会在测试方法执行前先执行

@After:某一测试方法中若加入了@After注解以后,那么此方法中的功能会在测试方法执行后执行

public class Test1 {
    @Before
    public void init(){
        System.out.println("测试方法开始了");
    }
    @After
    public void close(){
        System.out.println("测试方法结束了");
    }
    @Test
    public void test1(){
        System.out.println("测试1执行中……");
    }
    @Test
    public void test2(){
        System.out.println("测试2执行中……");
    }
}

注解

注解:注解其实就是代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取并执行相应的处理。通过使用注解,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具,可以通过这些补充信息进行验证或者进行部署

注解开发优势:现在主流开发都是基于注解方式,代码量少,框架可以根据注解去自动生成很多代码,从而减少代码量,程序更易读,如最火爆的springboot就是完全基于注解技术实现的。

注意:

  • 使用注解时要在其前面加@符号,并把注解当成一个修饰符使用。用于修饰它支持的程序元素
  • 注解一般和反射配套使用(就是一个标记,被读到便可修改相关内容)

注解分类

  1. JDK自带注解
  2. 元注解
  3. 自定义注解

JDK注解

  • @Override:用来标识此方法是重写的方法
  • @Deprecated:用于表示修饰的元素(类、方法、构造器、属性)已过时
  • @SuppressWarnings(“unused”)忽略警告(不仅可以放在类上也可以放在方法上)
  • @SafeVararys:堆污染

元注解

含义:用来描述注解的注解

  • @Target:表明注解用在哪,类上?方法上?
  • @Retention:注解的生命周期(Runtime>Class>Source)
  • @Inherited:父类加上该注解修饰的注解,那么子类也相当于加上该注解修饰的注解
  • @Documented:生成javadoc时会包含该注解
  • @Repeatable:注解为可重复型注解(就是可以在一个地方放多个) 

自定义注解

自定义注解格式

@Target({ElementType.METHOD,ElementType.TYPE})//可以加在方法&类上——用来表示元注解
@Retention(RetentionPolicy.RUNTIME)//到运行时都有效
@interface 注解名{
    属性类型 属性名1() [default 属性值1];
    属性类型 属性名2() [default 属性值2];//[]内部的东西代表可以不写
}
//下面以rice注解为例

注意:

  • 元注解应定义在注解上面
  • 定义注解只能使用public/默认修饰符
  • 注解内部的属性可以为0个或多个
  • 内部没有定义参数的注解叫做标记,内部定义参数的注解叫做元数据
  • 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口 

@Target(属性)

属性值内部可选项:

  • Element.TYPE:表明此注解可以用在类上
  • Element.METHOD:表明此注解可以用在方法上
  • Element.FIELD:表明此注解可以用在字段或属性上
  • Element.ANNOTATION_TYPE:表明此注解可以用在注解类型上
  • Element.CONSTRUCTOR:表明此注解可以用在构造函数
  • Element.LOCAL_VARIABLE:表明此注解可以用在局部变量上
  • Element.PACKAGE:表明此注解可以用在包声明上
  • Element.PARAMETER:表明此注解可以用在方法的参数上

注意:

  • 如果没规定使用位置的注解,则他放到哪都可以
  • 注解在同包中有效,如果要在不同包中有效则需要设置public属性(一个源文件中只能有一个public类)
  • 属性名为value,属性值为1个数组,如果有多个可选项那么总体用{}包裹起来(也可以写成value={})中间用逗号隔开 

@Retention(RetentionPolicy.属性名)

属性名:

  • SOURCE:在源文件中有效(当java文件编译成.class文件时被遗弃)
  • CLASS:在class文件中有效(当jvm加载class文件时被遗弃)
  • RUNTIME:在运行时都有效

注意:

  • 属性名只能三选一 
  • 如果注解没有加@Retention元注解,那么相当于默认的注解就是在class文件中有效
  • 生命周期排序:runtime>class>source

注解的内部属性

注解属性的类型:基本数据类型、string类型、枚举类型、注解类型、以上类型的数组。

普通属性

注解属性的定义:int age();

注解的属性都可以设置默认值:int age() default 0;

数组类型注解属性定义

  • 设置默认值:int[] ages() default {1,2,3,4,5,6}; 
  • 不设置默认值:int[] age();

注意:

  • 如果不设置默认值则使用注解时必须给其属性赋值eg:@rice(age=8)、eg:@rice(ages={1,2,3,4,5,6}) 
  • 当有多个内部属性没有设置默认值是,要想使用注解,则需要将多个属性赋值,多个属性之间用逗号隔开
  • 如果此属性有了默认值,同时在使用注解时也给此属性赋予了新值,则默认值会被新值覆盖。

特殊属性value

设置属性:

  • 不设默认值:int value();
  • 设置默认值:int value() default 0;

使用:

  • 单个属性:@rice(value=5)可以简写成@rice(5)
  • 多个属性:@rice(age=8,value=5)不能简写

注意:特殊属性的定义与别的属性相同,主要是使用方式不同(比如单个属性的话相对于普通属性可以简写,但是多个属性不行)

枚举

含义:一枚一枚的列举出来,但是个数是有限的、能穷尽的

自定义枚举类

定义枚举类

public class Season {
    //属性
   private final String seasonName;//季节名字
   private final String seasonDesc;//季节描述
    //利用构造器对属性赋值
    //构造器私有化,外界不能调用这个构造器,只能season自己调用
    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 WINTER=new Season("冬天","冰天雪地");
    //提供get方法,外界可以获取对象属性
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }
    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}

测试枚举类

public class Test1 {
    public static void main(String[] args) {
        //获取枚举对象
        Season summer = Season.SUMMER;
        System.out.println(summer.toString());//Season{seasonName='夏天', seasonDesc='烈日炎炎'}
        System.out.println(summer.getSeasonName());//夏天
        System.out.println(summer.getSeasonDesc());//烈日炎炎
    }
}

enum关键字创建枚举类

枚举类结构(用例)

public enum Season {
    //提供枚举类有限的,确定的对象——外界可以通过类名直接调用获得对象——>enum枚举类要求对象放在最开始的位置上
    SPRING("春天","春暖花开"),
    SUMMER("夏天","烈日炎炎"),
    AUTUMN("秋天","硕果累累"),
    WINTER("冬天","冰天雪地");
    //属性名
   private final String seasonName;//季节名字
   private final String seasonDesc;//季节描述
    //利用构造器对属性赋值
    //构造器私有化,外界不能调用这个构造器,只能season自己调用
    private Season(String seasonName, String seasonDesc){
        this.seasonName=seasonName;
        this.seasonDesc=seasonDesc;
    }
    //提供get方法,外界可以获取对象属性
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }
}

注意:

  • 以enum关键字定义枚举类
  • 枚举类提供的枚举对象必须放在结构的最上面,并且多个对象之间用逗号隔开,最后的对象用分号结束
  • 枚举对象可以通过类名.枚举对象名直接调用
  • 枚举对象的属性可以通过get方法直接获取
  • 以enum关键字定义的枚举类上层的父类为java.lang.Enum,并且Enum类对toString方法进行了重写,重写后的toString方法直接返回对应的枚举对象名

枚举类测试

public class Test {
    public static void main(String[] args) {
        Season autumn = Season.AUTUMN;
        System.out.println(autumn);//AUTUMN
        System.out.println(autumn.getSeasonName());//秋天
    }
}

空参枚举对象的枚举类

public enum Season {
    //这里面一共4个枚举对象
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;
}

理解:因为此枚举类底层没有属性、构造器、get方法,本来枚举对象应写成对象名(),但是()在没有属性的情况下也可以省略

枚举类的常用方法

toString

语法:枚举对象.toString()

返回值:枚举对象名

        Season autumn = Season.AUTUMN;
        System.out.println(autumn.toString());//AUTUMN

values

语法:枚举类名.values()

返回值:所有枚举对象的数组

        Season[] values = Season.values();
        System.out.println(Arrays.toString(values));//[SPRING, SUMMER, AUTUMN, WINTER]

valueof

语法:枚举类名.valueof("枚举对象名")

返回值:对应的枚举对象

        Season spring = Season.valueOf("SPRING");
        System.out.println(spring);//SPRING

枚举类实现接口

前言:枚举类实现接口可以让枚举类的每个枚举对象都实现接口

接口

public interface TestInterface {
    void show();
}

枚举类

public enum People implements TestInterface {
    MAN{
        @Override
        public void show() {
            System.out.println("男人");
        }
    },
    WOMAN{
        @Override
        public void show() {
            System.out.println("女人");
        }
    };
}

测试类

    public static void main(String[] args) {
        People man = People.MAN;
        man.show();//男人
        People woman = People.WOMAN;
        woman.show();//女人
    }