Junit单元测试、反射、注解【详解】

目录

1.Junit单元测试

        1.概念:

        2.怎么做:

        3.断言机制:

        4.测试注解:

2.反射

        1.概念:

        2.需要掌握的API

                1.获取字节码对象三种方式+Class类型

                2.获取构造器 Constructor

                3. 获取成员方法Method

                4.获取成员属性Field

        注意:绕过权限检查 setAccessable(true)

3.注解


1.Junit单元测试

        1.概念:

                针对最小的功能(方法),完成单独测试,测试该方法正确性

        2.怎么做:

                1.导入jar包依赖

                2.在测试类中 设计测试方法(格式)

                        1.无参

                        2.无返回值

                        3.公共的        

                        4.@Test:注解:让程序知道这里是做测试的方法。

                3.测试

                        前面会有 绿色箭头 点击即可 或者右键 run运行

                        如果是ok 绿色 否则 红色

        3.断言机制:

                断言:即预测divide的值 应该等于预期的2.如果不符合预期,这个方法会抛出异常,单元测试不通过 Assert.assertEquals(预测结果, 实际结果);

        4.测试注解:

        

package com.itheima.day14.teacher.demo01_junit;
//案例一:
import org.junit.*;

/**
 * 单元测试的注解:
 *  1. @Test:加在实例方法(非静态方法)上,idea会给方法提供运行按钮,可以直接运行这个方法
 *  2. @Before:加在实例方法上。方法会在 每次运行@Test方法之前,先执行一次
 *  3. @After:加在实例方法上。方法会在 每次运行@Test方法之后,再执行一次
 *  4. @BeforeClass:加在静态方法上。方法会在整个类里所有@Test之前执行,只执行一次
 *  5. @AfterClass:加在静态方法上。方法会在整个类里所有@Test之后执行,只执行一次
 * 使用场景:
 *   所有的前置的注解@Before、@BeforeClass,通常用于初始化一些资源
 *   所有的后置的注解@After、@AfterClass,用于用于最终的资源释放

 */
public class Demo02Test {
    @Test
    public void test1(){
        System.out.println("test1");
    }

    @Test
    public void test2(){
        System.out.println("test2");
    }

    @Before
    public void before(){
        System.out.println("--before--");
    }

    @After
    public void after(){
        System.out.println("--after--");
    }

    @BeforeClass
    public static void beforeAll(){
        System.out.println("==beforeClass==");
    }

    @AfterClass
    public static void afterAll(){
        System.out.println("==afterClass==");
    }
}


----------------------
//案例二:
package com.itheima.day14.teacher.demo01_junit;

public class MathUtil {
    /**
     * 判断一个数字是否偶数。这个方法是正确的
     */
    public static boolean isEven(int n){
        return n % 2 == 0;
    }

    /**
     * 两数相除。a 除以 b。 这个方法是有问题的
     */
    public static int divide(int a, int b){
        return b / a;
    }
}


---
package com.itheima.day14.teacher.demo01_junit;

import org.junit.Assert;
import org.junit.Test;


public class Demo01MathUtilTest {

    @Test
    public void testIsEven(){
        boolean even = MathUtil.isEven(10);
        //断言:即预测even的值是true。如果值不符合预期,这个方法会抛出异常,单元测试不通过
        Assert.assertTrue(even);
    }

    @Test
    public void testDivide(){
        int divide = MathUtil.divide(6, 3);
        //断言:即预测divide的值 应该等于预期的2.如果不符合预期,这个方法会抛出异常,单元测试不通过
        Assert.assertEquals(2, divide);
    }

    @Test
    public void test1(){
        //方法不抛异常,所以测试结果是 测试通过
        System.out.println("xxxxx");
    }

    @Test
    public void test2(){
        //方法会抛异常,所以测试结果是 测试不通过
        int i = 1/0;
    }
}

2.反射

        1.概念:

                就是加载类字节码文件到内存,以编程方式 解剖类中各个成分(构造器,成员属性,成员方法) 。   

                就是将类中各个成分封装成了对应对象的过程。

        2.需要掌握的API
                1.获取字节码对象三种方式+Class类型

                        Class.forName(包名+类名) jvm去加载该包下的类到内存。

                        类名.class 类文件到内存

                        对象.getClass() 类优先于对象到内存,且对象是基于类产生。

                        String.class            int.class         Integer.class等等

                

package com.itheima.day14.teacher.demo02_reflect;

import org.junit.Test;

/**
 
 */
public class Demo01Class {

    /**
     * 获取类的Class:
     */
    @Test
    public void testClass() throws ClassNotFoundException {
        //类名.class
        Class<Student> clazz = Student.class;
        System.out.println("clazz = " + clazz);

        //对象.getClass()
        Student stu = new Student();
        Class<? extends Student> clazz2 = stu.getClass();
        System.out.println("clazz2 = " + clazz2);

        //Class.forName("全限定类名")
        Class<?> clazz3 = Class.forName("demo02_reflect.Demo01Class");
        System.out.println("clazz3 = " + clazz3);
    }

    /**
     * 从Class对象里获取类的信息
     */
    @Test
    public void testClass2(){
        Class<Student> clazz = Student.class;

        //获取完整类名:demo02_reflect.Student
        System.out.println(clazz.getName());
        //获取简单类名:Student
        System.out.println(clazz.getSimpleName());
    }
}



--------------------------
package com.itheima.day14.teacher.demo02_reflect;

import org.junit.Test;

public class Demo01Class {

    /**
     * 获取类的Class:
     */
    @Test
    public void testClass() throws ClassNotFoundException {
        //类名.class
        Class<Student> clazz = Student.class;
        System.out.println("clazz = " + clazz);

        //对象.getClass()
        Student stu = new Student();
        Class<? extends Student> clazz2 = stu.getClass();
        System.out.println("clazz2 = " + clazz2);

        //Class.forName("全限定类名")
        Class<?> clazz3 = Class.forName("demo02_reflect.Demo01Class");
        System.out.println("clazz3 = " + clazz3);
    }

    /**
     * 从Class对象里获取类的信息
     */
    @Test
    public void testClass2(){
        Class<Student> clazz = Student.class;

        //获取完整类名:demo02_reflect.Student
        System.out.println(clazz.getName());
        //获取简单类名:Student
        System.out.println(clazz.getSimpleName());
    }
}
   2.获取构造器 Constructor

                        

package com.itheima.day14.teacher.demo02_reflect;

public class Student {
    public String name;
    private Integer age;

    public Student() {
    }

    private Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public void eat(String food){
        System.out.println("吃" + food);
    }

    private String sleep(int time){
        System.out.println("睡" + time + "小时");
        return "睡不醒";
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


----------------
package com.itheima.day14.teacher.demo02_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;

/**
 * 构造方法:用于创建类的实例对象的
 * 调用构造方法的方式有两种:
 *  普通方式:new 构造方法名(实参列表)
 *  反射方式:
 *      1. 先获取类的Class
 *      2. 从Class里获取构造方法对应的Constructor
 *          clazz.getConstructors():得到Constructor[],获取类里所有的public构造方法
 *          clazz.getDeclaredConstructors():得到Constructor[],获取类里所有的构造方法
 *          clazz.getConstructor(Class... parameterTypes):根据形参类型,找到对应的public构造方法
 *          clazz.getDeclaredConstructor(Class... parameterTypes):根据形参类型,找到对应的构造方法
 *      3. 调用Constructor的方法,就会生成类的实例对象
 *          constructor.newInstance(Object... args):调用构造方法并传入构造参数,得到生成的实例对象
 *          constructor.setAccessible(boolean flag):设置一下,是否允许暴力反射调用
 */
public class Demo02Constructor {
    /**
     * 获取一批构造方法
     */
    @Test
    public void testGetConstructors(){
        //1. 先获取类的Class
        Class<Student> clazz = Student.class;
        //2. 获取所有public构造方法
        // Constructor<?>[] constructors = clazz.getConstructors();
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("constructor = " + constructor);
        }
    }

    /**
     * 获取某一个构造方法
     */
    @Test
    public void testGetConstructor() throws NoSuchMethodException {
        //1. 先获取类的Class
        Class<Student> clazz = Student.class;

        //2. 获取无参的构造方法
        Constructor<Student> constructor = clazz.getConstructor();
        System.out.println("constructor = " + constructor);

        //3. 获取全参构造方法:
        // 是private的,所以要使用getDeclaredConstructor方法
        // 如果要获取有参的构造方法,需要getDeclaredConstructor传入 构造方法的形参类型列表
        //   要查找第一个形参是String类型的,第二个形参是Integer类型的 构造方法
        Constructor<Student> constructor1 = clazz.getDeclaredConstructor(String.class, Integer.class);
        System.out.println("constructor1 = " + constructor1);
    }

    /**
     * 反射调用无参构造方法 创建实例对象
     */
    @Test
    public void testNewInstance1() throws Exception {
        //1. 获取类的Class
        Class<Student> clazz = Student.class;
        //2. 获取无参构造方法
        Constructor<Student> constructor = clazz.getConstructor();
        //3. 调用无参构造,得到实例对象
        Student student = constructor.newInstance();
        System.out.println("student = " + student);

        Student student1 = new Student();
        System.out.println("student1 = " + student1);
    }

    /**
     * 反射调用有参构造,创建实例对象
     */
    @Test
    public void testNewInstance2() throws Exception {
        //1. 获取类的Class
        Class<Student> clazz = Student.class;
        //2. 获取无参构造方法
        Constructor<Student> constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
        //3. 因为是private的,所以需要暴力反射
        constructor.setAccessible(true);
        //4. 调用无参构造,得到实例对象
        Student student = constructor.newInstance("郭宇", 18);
        System.out.println("student = " + student);
    }
}

  3. 获取成员方法Method

package com.itheima.day14.teacher.demo02_reflect;

/**

 */
public class Student {
    public String name;
    private Integer age;

    public Student() {
    }

    private Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public void eat(String food){
        System.out.println("吃" + food);
    }

    private String sleep(int time){
        System.out.println("睡" + time + "小时");
        return "睡不醒";
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


------------------------
package com.itheima.day14.teacher.demo02_reflect;

import org.junit.Test;

import java.lang.reflect.Method;

/**
 * 调用一个对象的方法,有两种方式,最终效果相同:
 *  普通方式:Object res = 对象.方法名(实参列表);
 *  反射方式:
 *      1. 先获取类的Class
 *      2. 从Class里获取普通方法对应的Method
 *          clazz.getMethods():获取所有public方法
 *          clazz.getDeclaredMethod():获取所有方法
 *          clazz.getMethod(String name, Class... parameterTypes):获取指定public方法
 *          clazz.getDeclaredMethod(String name, Class... parameterTypes)
 *      3. 反射调用Method,传入方法的实参,得到方法的返回值
 *          Object res = method.invoke(对象, 实参列表)
 */
public class Demo03Method {

    /**
     * 反射调用public方法:Student的eat方法
     */
    @Test
    public void test1() throws Exception {
        Student student = new Student();
        student.eat("爆肚面");
        System.out.println("----------------");

        //1. 获取Class
        Class<? extends Student> clazz = student.getClass();
        //2. 获取Method:获取名称为eat,第一个形参是String的方法
        Method eatMethod = clazz.getMethod("eat", String.class);
        //3. 调用Method:method.invoke(对象, 实参列表)
        Object res = eatMethod.invoke(student, "鸡");
        System.out.println("res = " + res);
    }

    /**
     * 反射调用private方法:sleep
     */
    @Test
    public void test2() throws Exception {
        Student s = new Student();

        //1. 获取Class
        Class<? extends Student> clazz = s.getClass();
        //2. 获取Method
        Method sleepMethod = clazz.getDeclaredMethod("sleep", int.class);
        //3. 设置允许暴力反射
        sleepMethod.setAccessible(true);
        //4. 反射调用Method
        Object res = sleepMethod.invoke(s, 8);
        System.out.println("res = " + res);
    }
}
    4.获取成员属性Field

    package com.itheima.day14.teacher.demo02_reflect;


    public class Student {
        public String name;
        private Integer age;

        public Student() {
        }

        private Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public void eat(String food){
            System.out.println("吃" + food);
        }

        private String sleep(int time){
            System.out.println("睡" + time + "小时");
            return "睡不醒";
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }



---------------------
package com.itheima.day14.teacher.demo02_reflect;

import org.junit.Test;

import java.lang.reflect.Field;

/**
 * 反射操作成员变量,两种方式,最终效果相同:
 *  普通方式:
 *      对象.成员变量名 = 值
 *      Object value = 对象.成员变量名
 *  反射方式:
 *      1. 获取类的Class
 *      2. 从Class里获取成员变量对应的Field
 *          clazz.getFields():获取所有public的成员变量
 *          clazz.getDeclaredFields():获取所有成员变量
 *          clazz.getField(String fieldName):获取一个public的成员变量
 *          clazz.getDeclaredField(String fieldName):获取一个成员变量
 *      3. 反射操作Field,赋值或取值
 *          field.set(对象, 值):给成员变量赋值
 *          Object value = field.get(对象):取成员变量的值
 */
public class Demo04Field {

    /**
     * 操作public的field
     */
    @Test
    public void test1() throws NoSuchFieldException, IllegalAccessException {
        Student s = new Student();

        //1. 获取Class
        Class<? extends Student> clazz = s.getClass();
        //2. 获取Field
        Field nameField = clazz.getField("name");
        //3. 操作Field
        //  给成员变量赋值
        nameField.set(s, "小明");
        System.out.println(s);
        //  反射取成员变量值
        Object value = nameField.get(s);
        System.out.println("value = " + value);
    }

    /**
     * 反射操作age成员变量
     */
    @Test
    public void test2() throws Exception {
        Student s = new Student();

        //1. 获取Class
        Class<? extends Student> clazz = s.getClass();
        //2. 获取Field
        Field ageField = clazz.getDeclaredField("age");
        //3. 反射操作Field
        ageField.setAccessible(true);
        ageField.set(s, 18);
        System.out.println("s = " + s);

        Object value = ageField.get(s);
        System.out.println("value = " + value);
    }
}
        注意:绕过权限检查 setAccessable(true)

3.注解

        1.注解:就是用于在代码标识,被程序解析

                编译检查 @Override

                让程序指定特定操作,@Test

        2.注解的定义

                public @Interface 注解名{}

                属性 属性类型 属性名() default 默认值;

                value注解可以省略,其他属性不用赋值情况下。

        3.元注解:修饰注解的注解

                常见的两种:

        

        4.通过反射机制解析 注解 注解一种对象 Annotation对象

package com.itheima.day14.teacher.demo03_anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnno {
    int age() default 18;
    boolean status() default false;
    String value();
}


--------------------
package com.itheima.day14.teacher.demo03_anno;

import java.util.Date;

/**

 */
@SuppressWarnings(value = {"unused"})
public class Demo01 {

    /**
     * 如果方法上加了@Override:这个注解本身没有任何功能
     * 作用是:给idea看的。
     *  当idea发现某个方法上有这个注解,idea就会帮我们检查 这个方法是否符合重写的语法要求
     *  如果不符合,idea会报错
     */
    @Override
    public String toString() {
        return "Demo01{}";
    }

    public static void main(String[] args) {
        Demo01 demo01 = new Demo01();
        System.out.println(demo01);

        Date date = new Date(2024, 3, 21);
        System.out.println("date = " + date);

        String abc = "abc";
    }
}


-------------------
package com.itheima.day14.teacher.demo03_anno;

import java.lang.reflect.Method;
import java.util.Arrays;

/**

 */
@SuppressWarnings("all")
@MyAnno(status = false, value = "abc")
public class Demo02MyAnno {

    @MyAnno(age = 28, status = true, value = "ac")
    public void show(){
        System.out.println("show");
    }

    /**
     * 1.自定义一个注解MyAnno;其中包含一些属性
     * 2.定义一个类,类里show方法上加MyAnno注解,并给属性赋值
     * 3.在类里写一个main方法, 判断show方法上有没有MyAnno注解;如果有,就获取配置的注解对象,并取参数值打印出来
     */
    @MyAnno("xxx")
    public static void main(String[] args) throws NoSuchMethodException {
        //要求:判断一下show方法上有没有MyAnno注解;如果有的话,就获取注解配置的属性参数值
        // 获取类的Class
        Class<Demo02MyAnno> clazz = Demo02MyAnno.class;
        // 从类的Class获取show方法的Method
        Method showMethod = clazz.getMethod("show");
        // 再调用Method对象的isAnnotationPresent方法,判断有没有MyAnno注解
        boolean b = showMethod.isAnnotationPresent(MyAnno.class);
        System.out.println("Demo02MyAnno类里的show方法上是否有@MyAnno注解:" + b);

        //就获取注解配置的属性参数值
        MyAnno myAnno = showMethod.getAnnotation(MyAnno.class);
        System.out.println(myAnno.age());
        System.out.println(myAnno.status());
        System.out.println(myAnno.value());

        System.out.println("------------------------");
        //@SuppressWarnings这个注解的功能,idea是怎么实现的?
        //  判断类上有没有@Suppresswarnings注解,如果有的话获取value值。根据value值不同,压制不同的警告
        //  这里得到结果是false,注解不存在。
        //  原因是:@SuppressWarnings的RetentionPolicy是SOURCE,只保留到源码阶段;而这里通过反射判断有没有注解,反射是在运行时阶段的
        boolean suppressWarnings = clazz.isAnnotationPresent(SuppressWarnings.class);
        System.out.println(suppressWarnings);
        if (suppressWarnings) {
            SuppressWarnings annotation = clazz.getAnnotation(SuppressWarnings.class);
            String[] value = annotation.value();
            System.out.println("要压制的警告有:" + Arrays.toString(value));
        }
    }
}

        

                         

        

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值