JAVASE单元测试、发射 | 豆包MarsCode AI刷题

37 阅读7分钟

一、单元测试

1.1 介绍

单元测试:针对最小的功能单元,编写测试代码对其进行正确性测试。

为了测试更加方便,有一些第三方的公司或者组织提供了很好用的测试框架,给开发者使用。Junit是第三方公司开源出来的,用于对代码进行单元测试的工具(IDEA已经集成了junit框架)。相比于在main方法中测试有如下几个优点。

  • 能灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。
  • 不需要程序员分析测试结果,会自动生成测试报告

先准备一个类:

public class StringUtil {
    public static void printNumber(String name){
        System.out.println("名字长度:"+name.length());
    }
}
​

为之写一个测试类:

import org.junit.Test;
public class StringUtilTest {
    @Test
    public void testPrintNumber(){
        StringUtil.printNumber("admin");
        StringUtil.printNumber(null);
    }
​
}
​

1.2 单元测试断言

断言:程序员可以预测程序的运行结果,检查程序的运行结果是否与预期一致。

在StringUtil类中新增一个测试方法

 public static int getMaxIndex(String data){
     if(data == null){
         return -1;
     }
     return data.length();
 }

接下来,我们在StringUtilTest类中写一个测试方法

public class StringUtilTest{
    @Test
    public void testGetMaxIndex(){
       int index1 = StringUtil.getMaxIndex(null);
       System.out.println(index1);
        
       int index2 = StringUtil.getMaxIndex("admin");
       System.out.println(index2);
        
        //断言机制:预测index2的结果
        Assert.assertEquals("方法内部有Bug",4,index2);
    }
}

运行测试方法表示我们预期值与实际值不一致

1.3 Junit框架的常用注解

下面进行测试:

public class StringUtilTest{
    @Before
    public void test1(){
        System.out.println("--> test1 Before 执行了");
    }
    @BeforeClass
    public static void test11(){
        System.out.println("--> test11 BeforeClass 执行了");
    }
    @After
    public void test2(){
        System.out.println("--> test2 After 执行了");
    }
    @AfterCalss
    public static void test22(){
        System.out.println("--> test22 AfterCalss 执行了");
    }
}

应用场景:

假设我想在每个测试方法中使用Socket对象,并且用完之后,需要把Socket关闭。代码就可以按照下面的结构来设计

public class StringUtilTest{
    private static Socket socket;
    @Before
    public void test1(){
        System.out.println("--> test1 Before 执行了");
    }
    @BeforeClass
    public static void test11(){
        System.out.println("--> test11 BeforeClass 执行了");
        //初始化Socket对象
        socket = new Socket();
    }
    @After
    public void test2(){
        System.out.println("--> test2 After 执行了");
    }
    @AfterCalss
    public static void test22(){
        System.out.println("--> test22 AfterCalss 执行了");
         //关闭Socket
        socket.close();
    }
}

二、反射

反射技术:指的是加载类的字节码到内存,并以编程的方法解刨出类中的各个成分(成员变量、方法、构造器等)。

  • 加载类,获取字节码对象 class对象
  • 获取类的构造器:constructor对象
  • 获取类的成员变量:Filed对象
  • 获取类的成员方法:Method对象

2.1 获取类的字节码

将字节码加载到内存,我们需要获取到的字节码对象。

import javaday01.Student;
public class Test1Class {
    public static void main(String[] args) throws Exception {
        Class c1 = Student.class;
        System.out.println(c1.getName());//类的全名
        System.out.println(c1.getSimpleName());//获取简单类名
​
        Class c2 = Class.forName("javaday01.Student");
        System.out.println(c1 == c2); //true
​
        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c2==c3); // true
    }
}
​

2.2 获取类的构造器

上一节我们已经可以获取到类的字节码对象了。接下来,我们学习一下通过字节码对象获取构造器,并使用构造器创建对象。

写一个类Cat

package javaday01;
​
public class Cat {
    private String name;
    private int age;
​
    public Cat(){}
    public Cat(String name, int age){}
​
}
​
  • getDeclaredConstructors()
package javaday01;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class Test2Constructor {
    @Test
    public void testGetConstructor(){
        //1. 获取这个类的class对象
        Class c = Cat.class;
        //2 .获取这个类的全部构造器(只要存在就能拿到)
        Constructor[] constructors = c.getDeclaredConstructors();
        // 输出
        for(Constructor constructor : constructors){
            System.out.println(constructor.getName()+"--->参数个数: "+constructor.getParameterCount());
        }
    }
}
  • 单个构造器
package javaday01;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class Test2Constructor {
    @Test
    public void testGetConstructor() throws Exception{
        //1. 获取这个类的class对象
        Class c = Cat.class;
        //2 .获取这个类的全部构造器(只要存在就能拿到)
        //Constructor[] constructors = c.getDeclaredConstructors();

//        // 输出
//        for(Constructor constructor : constructors){
//            System.out.println(constructor.getName()+"--->参数个数: "+constructor.getParameterCount());
//        }
        // 获取某个构造器(只能是public)
        Constructor constructor1 = c.getConstructor();
        System.out.println(constructor1.getName()+"---> 参数个数:"+constructor1.getParameterCount());

        // 获取private的
        Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor2.getName()+"---> 参数个数:"+constructor2.getParameterCount());



    }


}

2.3 反射获取构造器的作用

构造器的作用:初始化对象并返回

由于构造器是private修饰的,先需要调用setAccessible(true) 表示禁止检查访问控制,然后再调用newInstance(实参列表) 就可以执行构造器,完成对象的初始化了。

package javaday01;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class Test2Constructor {
    @Test
    public void testGetConstructor() throws Exception{
        //1. 获取这个类的class对象
        Class c = Cat.class;
        //2 .获取这个类的全部构造器(只要存在就能拿到)
        //Constructor[] constructors = c.getDeclaredConstructors();

//        // 输出
//        for(Constructor constructor : constructors){
//            System.out.println(constructor.getName()+"--->参数个数: "+constructor.getParameterCount());
//        }
        // 获取某个构造器(只能是public)
        Constructor constructor1 = c.getConstructor();
        System.out.println(constructor1.getName()+"---> 参数个数:"+constructor1.getParameterCount());
        constructor1.setAccessible(true);
        Cat cat = (Cat) constructor1.newInstance();
        System.out.println(cat);


        // 获取private的
        Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor2.getName()+"---> 参数个数:"+constructor2.getParameterCount());
        constructor2.setAccessible(true);
        Cat cat2 = (Cat) constructor2.newInstance("叮当猫", 12);
        System.out.println(cat2);




    }


}

2.4 反射获取成员变量&使用

  • Cat类有如下成员变量:

    执行一下代码获取成员变量

    package javaday01;
    
    import org.junit.Test;
    
    import java.lang.reflect.Field;
    
    public class Test3Field {
        @Test
        public void testGetFiled() throws Exception{
            Class c = Cat.class;
            // 获取所有字段
            Field[] fields = c.getDeclaredFields();
            for (Field filed : fields){
                System.out.println(filed.getName() + "---> " + filed.getType());
            }
            // 获取某个字段
            Field fName = c.getDeclaredField("name");
            System.out.println(fName.getName() + "---> "+ fName.getType());
    
            Field fAge = c.getDeclaredField("age");
            System.out.println(fAge.getName() + "---> "+ fAge.getType());
    
    
    
    
    
        }
    }
    
  • 给成员变量赋值和获取值的方法

    package javaday01;
    
    import org.junit.Test;
    
    import java.lang.reflect.Field;
    
    public class Test3Field {
        @Test
        public void testGetFiled() throws Exception{
            Class c = Cat.class;
            // 获取所有字段
            Field[] fields = c.getDeclaredFields();
            for (Field filed : fields){
                System.out.println(filed.getName() + "---> " + filed.getType());
            }
            // 获取某个字段
            Field fName = c.getDeclaredField("name");
            System.out.println(fName.getName() + "---> "+ fName.getType());
    
            Field fAge = c.getDeclaredField("age");
            System.out.println(fAge.getName() + "---> "+ fAge.getType());
    
            //赋值
            Cat cat = new Cat();
            fName.setAccessible(true);
            fName.set(cat, "加菲猫");
            System.out.println(cat);
    
            //取值
            String name = (String) fName.get(cat);
            System.out.println(name);
    
    
    
    
    
    
    
    
        }
    }
    

2.5 反射获取成员方法

在Java中反射包中,每一个成员方法用Method对象来表示,通过Class类提供的方法可以获取类中的成员方法对象。如下下图所示

package javaday01;

import java.lang.reflect.Method;

public class Test3Method {
    public static void main(String[] args) {
        Class c = Cat.class;
        Method[] methods = c.getDeclaredMethods();

        for (Method method:methods){
            System.out.println(method.getName()+"-->"+method.getParameterCount()+"-->"+method.getReturnType());
        }

    }


}

执行上面的代码,运行结果如下图所示:打印输出每一个成员方法的名称、参数格式、返回值类型

在Method类中提供了方法,可以将方法自己执行起来。

package javaday01;

import java.lang.reflect.Method;

public class Test3Method {
    public static void main(String[] args) throws Exception {
        Class c = Cat.class;
        Method[] methods = c.getDeclaredMethods();

        for (Method method:methods){
            System.out.println(method.getName()+"-->"+method.getParameterCount()+"-->"+method.getReturnType());
        }

        Method run = c.getDeclaredMethod("run");
        Cat cat = new Cat();
        run.setAccessible(true);
        Object rs1 = run.invoke(cat);
        System.out.println(rs1);

        Method eat = c.getDeclaredMethod("eat",String.class);
        eat.setAccessible(true);
        Object rs2 = eat.invoke(cat,"鱼儿");
        System.out.println(rs2);




    }


}

2.6 反射的应用

反射的核心作用是用来获取类的各个组成部分并执行他们

让我们写一个框架,能够将任意一个对象的属性名和属性值写到文件中去。不管这个对象有多少个属性,也不管这个对象的属性名是否相同。

1.先写好两个类,一个Student类和Teacher类
2.写一个ObjectFrame类代表框本架
	在ObjectFrame类中定义一个saveObject(Object obj)方法,用于将任意对象存到文件中去
	参数:Object obj: 就表示要存入文件中的对象
	
3.编写方法内部的代码,往文件中存储对象的属性名和属性值
	1)参数obj对象中有哪些属性,属性名是什么实现值是什么,中有对象自己最清楚。
	2)接着就通过反射获取类的成员变量信息了(变量名、变量值)
	3)把变量名和变量值写到文件中去

写一个ObjectFrame表示自己设计的框架,代码如下图所示:

package javaday01;

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

public class ObjectFrame {
    public static void saveObject(Object obj) throws  Exception{
        PrintStream ps = new PrintStream(new FileOutputStream("D:\learn_java\javaday01\src\data.txt", true));
        Class c  = obj.getClass();
        ps.println("---------"+c.getSimpleName()+"---------");
        Field[] fields = c.getDeclaredFields();

        // 把变量名和变量值写入文件
        for(Field field : fields){
            String name = field.getName();
            //Object value = field.get(obj) + " ";
            ps.println(name);
        }
        ps.close();

    }
}

使用自己设计的框架,往文件中写入Student对象的信息和Teacher对象的信息。

package javaday01;

import org.junit.Test;

public class Test5Framw {
    @Test
    public void save() throws Exception{
        Student s1 = new Student(45, "jack");
        Teacher t1 = new Teacher("wendy", 30000);
        ObjectFrame.saveObject(s1);
        ObjectFrame.saveObject(t1);

    }

}

三、注解

3.1 定义

Java注解是代码中的特殊标记,比如@Override、@Test等,作用是:让其他程序根据注解信息决定怎么执行该程序。

  • 注解不光可以用在方法上,还可以用在类上、变量上、构造器上等位置。