06_单元测试与反射

单元测试

什么是单元测试
  • 就是针对最小的功能单位(方法),编写测试代码对其进行正确性测试
  • Junit 单元测试框架:可以用来对方法进行测试,它是第三方公司开源出来的(IDEA 以及集成了此框架)
注解 说明
@Test 测试类中的方法必须用它修饰才能成为测试方法,才能启动执行
@Before 用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次
@After 用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次
@BeforeClass 用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次
@AfterClass 用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次
  • 在测试方法执行前执行的方法,常用于:初始化资源
  • 在测试方法执行完后再执行的方法,常用于:释放资源
// 被测试的方法

/**
 * 字符串工具类
 */
public class StringUtil {
   
    public static void printNumber(String name) {
   
        if (name == null) {
   
            System.out.println(0);
            return;// 停掉方法
        }
        System.out.println("名字的长度是:" + name.length());
    }

    // 求字符串最大索引
    public static int getMaxIndex(String data) {
   
        if (data == null) {
   
            return -1;
        }
        return data.length();
    }

}
// 进行测试的类

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

/**
 * 测试类
 * 测试方法必须做到:公共、无参、无返回值
 * 测试方法上面必须声明 @Test 注解
 */

public class StringUtilTest {
   
    @Before
    public void test1() {
   
        System.out.println("------test1执行了------");
    }

    @Test
    public void testPrintNumber() {
   
        StringUtil.printNumber(null);
    }

    @Test
    public void testGetMaxIndex() {
   
        int index1 = StringUtil.getMaxIndex(null);
        System.out.println(index1);
        int index2 = StringUtil.getMaxIndex("admin");
        System.out.println(index2);

        // 断言机制:程序员可以通过预测业务方法的结果
        Assert.assertEquals("方法内部有bug!", 4, index2);
    }
}

反射

认识反射

反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器)

获取类
public class Test {
   
    public static void main(String[] args) throws Exception {
   
        // 获取Class对象的三种方式
        // 方式一
        Class c1 = Student.class;
        // 获取类的名字
        // 获取全类名  【全类名 = 包名.类的简名】
        System.out.println(c1.getName());  // login.Student ()
        // 获取类的简名
        System.out.println(c1.getSimpleName());  // Student

        // 方式二
        Class c2 = Class.forName("login.Student");
        System.out.println(c2 == c1);  // true

        // 方式三
        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c3 == c2);  // true
    }
}

class Student {
   
    private String name;
    private int age;
}
获取类的构造器
// Cat 类 (前置资源)

public class Cat {
   
    private String name;
    private int age;

    public Cat() {
   
    }

    public Cat(String name, int age) {
   
        this.name = name;
        this.age = age;
    }

    public String getName() {
   
        return name;
    }

    public void setName(String name) {
   
        this.name = name;
    }

    public int getAge() {
   
        return age;
    }

    public void setAge(int age) {
   
        this.age = age;
    }
}
// 第一部分展示

import java.lang.reflect.Constructor;

public class Test {
   
    public static void main(String[] args) throws Exception {
   
        // 1. 反射第一步:必须先得到这个类的 Class 对象
        Class c = Cat.class;

        // 2. 获取类的全部构造器
        // Constructor[] constructors = c.getConstructors();  // getConstructors 功能当构造器为私有时,获取不到
        Constructor[] constructors = c.getDeclaredConstructors();  // 不管是否私有,都能拿到全部的构造器

        // 3. 遍历数组中的每个构造器对象
        for (Constructor constructor : constructors) {
   
            System.out.println(constructor.getName() + "--->" +
                    constructor.getParameterCount());
        }
        /*
        * 运行结果:
        *
        *       login.Cat--->0
        *       login.Cat--->2
        * 
        * */
    }
}
// 第二部分展示

import java.lang.reflect.Constructor;

public class Test {
   
    public static void main(String[] args) throws Exception {
   
        // 1. 反射第一步:必须先得到这个类的 Class 对象
        Class c = Cat.class;

        // 2. 获取某个构造器:无参构造器
        Constructor constructor = c.getConstructor();
        System.out.println(constructor.getName() + "--->" +
                constructor.getParameterCount());  // login.Cat--->0

        // 3. 获取有参构造器
        Constructor constructor1 = c.getConstructor(String.class, int.class);
        System.out.println(constructor1.getName() + "--->" +
                constructor1.getParameterCount());  // login.Cat--->2

    }
}

获取类的构造器,有什么用吗?

获取类的构造器的作用,依然是初始化一个对象返回(这种初始化,可以实现暴力破解构造器中 private 的限制)

// Cat 类 (前置资源)

class Cat {
   
    private String name;
    private int age;
	
    // 重写了 toString 方法!
    @Override
    public String toString() {
   
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Cat() {
   
    }

    public Cat(String name, int age) {
   
        this.name = name;
        this.age = age;
    }

    public String getName() {
   
        return name;
    }

    public void setName(String name) {
   
        this.name = name;
    }

    public int getAge() {
   
        return age;
    }

    public void setAge(int age) {
   
        this.age = age;
    }
}
import java.lang.reflect.Constructor;

public class Test {
   
    public static void main(String[] args) throws Exception {
   
        // 1. 反射第一步:必须先得到这个类的 Class 对象
        Class c = Cat.class;

        // 2. 获取某个构造器:无参构造器
        Constructor constructor = c.getConstructor();
        System.out.println(constructor.getName() + "--->" +
                constructor.getParameterCount());  // login.Cat--->0

        // ---访问无参构造器的成员变量
        constructor.setAccessible(true);  // 当输入了这一句代码,意味着
        // 开启了"禁止检查访问权限"功能,即使构造器是私有的,也能实现访问成员变量,这个是暴力反射!
        Cat cat = (Cat) constructor.newInstance();
        System.out.println(cat);  // Cat{name='null', age=0}


        // 3. 获取有参构造器
        Constructor constructor1 = c.getConstructor(String.class, int.class);
        System.out.println(constructor1.getName() + "--->" +
                constructor1.getParameterCount());  // login.Cat--->2

        // ---访问有参构造器的成员变量
        Cat cat1 = (Cat) constructor1.newInstance("叮当猫", 3);
        System.out.println(cat1);  // Cat{name='null', age=0}
    }
}
获取类的成员变量
// Cat 类 (前置资源)

public class Cat {
   
    public static final String COUNTRY = "中国";
    public static int a;
    private String name;
    private int age;
    
    @Override
    public String toString() {
   
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Cat() {
   
    }

    public Cat(String name, int age) {
   
        this.name = name;
        this.age = age;
    }

    public String getName() {
   
        return name;
    }

    public void setName(String name) {
   
        this.name = name;
    }

    public int getAge() {
   
        return age;
    }

    public void setAge(int age) {
   
        this.age = age;
    }
}
import java.lang.reflect.Field;

public class Test {
   
    public static void main(String[] args) throws Exception {
   
        // 1. 反射第一步:必须是先得到类的 Class 对象
        Class c = Cat.class;

        // 2. 获取类的全部成员变量
        Field[] fields = c.getDeclaredFields();

        // 3. 遍历这个成员变量数组
        for (Field field : fields) {
   
            System.out.println(field.getName() + "--->" + field.getType());
        }
        System.out.println("----------------------------");

        // 4. 定位到某个成员变量
        Field fName = c.getDeclaredField("name");
        System.out.println(fName.getName() + "--->" + fName.getType());

        Field fAge = c.getDeclaredField("age");
        System.out.println(fAge.getName() + "--->" + fAge.getType());

        // 运行结果:
        /*
            COUNTRY--->class java.lang.String
            a--->int
            name--->class java.lang.String
            age--->int
            ----------------------------
            name--->class java.lang.String
            age--->int
        */
    }
}

获取成员变量的作用:依然是赋值、取值

import java.lang.reflect.Field;

public class Test {
   
    public static void main(String[] args) throws Exception {
   
        // 得到类的 Class 对象
        Class c = Cat.class;

        // 定位到某个成员变量
        Field fName = c.getDeclaredField("name");
        Field fAge = c.getDeclaredField("age");

        // 进行赋值
        Cat cat = new Cat();
        fName.setAccessible(true);  // 禁止访问控制权限
        fName.set(cat, "咖啡猫");
        System.out.println(cat);  // Cat{name='咖啡猫', age=0}

        // 进行取值
        String name = (String) fName.get(cat);
        System.out.println(name);  // 咖啡猫
    }
}
获取类的成员方法
import java.lang.reflect.Method;

public class Test {
   
    public static void main(String[] args) throws Exception {
   
        // 1. 得到类的 Class 对象
        Class c = Cat.class;

        // 2. 获取类的全部成员方法
        Method[] methods = c.getDeclaredMethods();

        // 3. 遍历数组中的每个方法对象
        for (Method method : methods) {
   
            System.out.println(method.getName() + "--->"
                    + method.getParameterCount() + "--->"
                    + method.getReturnType());
        }
        System.out.println("-----------------------");

        // 4. 获取某个方法对象
        Method run = c.getDeclaredMethod("run");  // 拿run方法,无参数的
        System.out.println(run.getName() + "--->"
                + run.getParameterCount() + "--->"
                + run.getReturnType());
        System.out.println("-----------------------");

        Method eat = c.getDeclaredMethod("eat", String.class);  // 拿eat方法,含参数的
        System.out.println(eat.getName() + "--->"
                + eat.getParameterCount() + "--->"
                + eat.getReturnType());

        // 5. 获取成员方法的作用:依然是执行
        Cat cat = new Cat();  // 先创造一个成员出来,才能执行成员方法

        run.setAccessible(true);  // 禁止检查访问权限 (暴力解除了 private 的限制)
        Object res1 = run.invoke(cat);
        System.out.println(res1);

        eat.setAccessible(true);  // 禁止检查访问权限 (暴力解除了 private 的限制)
        Object res2 = eat.invoke(cat, "鱼");
        System.out.println(res2);

        // 运行结果
        /*
            eat--->1--->class java.lang.String
            getAge--->0--->int
            setAge--->1--->void
            getName--->0--->class java.lang.String
            run--->0--->void
            toString--->0--->class java.lang.String
            setName--->1--->void
            -----------------------
            run--->0--->void
            -----------------------
            eat--->1--->class java.lang.String
            猫跑得快
            null
            猫最爱吃:鱼
         */
    }
}
应用场景
  • 基本作用:可以得到一个类的全部成分然后操作
  • 可以破坏封装性
  • 最重要的用途是:适合做 Java 的框架,基本上,主流的框架都会基于反射设计出一些通用的功能

案例:要求对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去

// 运行程序部分

public class Test {
   
    public static void main(String[] args) throws Exception {
   
        Student s1 = new Student("Jack", 29, '男', 168, "唱歌");
        Teacher t1 = new Teacher("Tony", 9000);
        // 需求:要求对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去
        String PATH = "E:/Desktop/temp.txt";
        System.out.println(ObjectFrame.savaObject(s1, PATH));
        System.out.println(ObjectFrame.savaObject(t1, PATH));
    }
}

class Student {
   
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;

    public Student(String name, int age, char sex, double height, String hobby) {
   
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.hobby = hobby;
    }
}

class Teacher {
   
    private String name;
    private double salary;

    public Teacher(String name, double salary) {
   
        this.name = name;
        this.salary = salary;
    }
}
// 框架部分

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class ObjectFrame {
   
    // 目的:可以保存任何对象的字段和其数据到文件中去
    public static boolean savaObject(Object obj, String path) throws Exception {
   
        // 创建打印输出流,待会保存数据到文件要用
        PrintStream ps = new PrintStream(new FileOutputStream(path, true));  // true 代表开启追加模式

        // obj 是任意对象,不清楚到达有多少个字段要保存
        Class c = obj.getClass();  // 通过对象拿到它的"类对象"
        String cName = c.getSimpleName();  // 通过"类对象"获取类的简单名
        ps.println("----------" + cName + "----------");

        // 从这个类中提取它的全部成员变量
        Field[] fields = c.getDeclaredFields();

        // 遍历,得到并操作每个成员对象
        for (Field field : fields) {
   
            String name = field.getName();  // 拿到该成员变量的名字
            field.setAccessible(true);  // 禁止检查访问权限 (通过暴力手段解除了 private 的限制)
            String value = field.get(obj) + "";  // 拿到对象在"该成员变量"中存的值
            ps.println(name + "=" + value);  // 将数据输出到文件中
        }
        ps.close();
        return true;
    }
}
// 路径"E:/Desktop/temp.txt"的文件内容

----------Student----------
name=Jack
age=29
sex=男
height=168.0
hobby=唱歌
----------Teacher----------
name=Tony
salary=9000.0

相关推荐

  1. 06_单元测试反射

    2023-12-05 19:00:01       31 阅读
  2. 软件测试--第五章-单元测试集成测试

    2023-12-05 19:00:01       12 阅读
  3. 软件测试——单元测试

    2023-12-05 19:00:01       36 阅读
  4. C#学习笔记3-函数单元测试

    2023-12-05 19:00:01       22 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-05 19:00:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-05 19:00:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-05 19:00:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-05 19:00:01       20 阅读

热门阅读

  1. vue3对象reactive()数据改变页面不刷新

    2023-12-05 19:00:01       36 阅读
  2. android11-隐藏状态栏和导航栏

    2023-12-05 19:00:01       28 阅读
  3. 【Rust与AI】概览和方向

    2023-12-05 19:00:01       30 阅读