单元测试
什么是单元测试
- 就是针对最小的功能单位(方法),编写测试代码对其进行正确性测试
- 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 {@Beforepublic void test1() {System.out.println("------test1执行了------");}@Testpublic void testPrintNumber() {StringUtil.printNumber(null);}@Testpublic 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 方法!@Overridepublic 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;@Overridepublic 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.Stringa--->intname--->class java.lang.Stringage--->int----------------------------name--->class java.lang.Stringage--->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.StringgetAge--->0--->intsetAge--->1--->voidgetName--->0--->class java.lang.Stringrun--->0--->voidtoString--->0--->class java.lang.StringsetName--->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