JAVA单元测试、反射
一、单元测试
- 单元测试就是针对最小的功能单元(方法),编写测试代码对该功能进行正确性测试。
1、Junit单元测试框架
- JUnit是使用Java语言实现的单元测试框架,它是第三方公司开源出来的,很多开发工具已经集成了Junit框架,比如IDEA。
优点
- 编写的测试代码很灵活,可以指定某个测试方法执行测试,也支持一键完成自动化测试。
- 不需要程序员去分析测试的结果,会自动生成测试报告出来。
- 提供了更强大的测试能力。
具体步骤
- 将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了)
- 编写测试类、测试类方法(注意:测试方法必须是公共的,无参数,无返回值的非静态方法)
- 必须在测试方法上使用@Test注解(标注该方法是一个测试方法)
- 在测试方法中,编写程序调用被测试的方法即可。
- 选中测试方法,右键选择“JUnit运行” ,如果测试通过则是绿色;如果测试失败,则是红色。
2、Junit框架的常见注解
Junit单元测试框架的常用注解(Junit 4.xxxx版本)
- 开始执行的方法:初始化资源。
- 执行完之后的方法:释放资源。
Junit单元测试框架的常用注解(Junit 5.xxxx版本)
- 开始执行的方法:初始化资源。
- 执行完之后的方法:释放资源。
/*** 字符串工具类*/
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() - 1;}
}
/*** 测试类*/
public class StringUtilTest {@BeforeClasspublic static void test11(){System.out.println("---> test11 BeforeClass 执行了---------");}@Beforepublic void test1(){System.out.println("---> test1 Before 执行了---------");}@Afterpublic void test2(){System.out.println("---> test2 After 执行了---------");}@AfterClasspublic static void test22(){System.out.println("---> test22 AfterClass 执行了---------");}@Test // 测试方法public void testPrintNumber(){StringUtil.printNumber("admin");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);}
}
二、反射
- 反射指的是允许以编程方式访问已加载类的成分(成员变量、方法、构造器等)。
1、获取类
- 反射的第一步都是先得到加载后的类,然后才可以去那类的其他成分。
- 获取Class类的对象的三种方式
(1)方式一:Class c1 = Class.forName(“全类名”);
(2)方式二:Class c2 = 类名.class
(3)方式三:Class c3 = 对象.getClass();
/*** 获取Class对象。*/
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()); // 简名:StudentClass c2 = Class.forName("com.csdn.d2_reflect.Student");System.out.println(c1 == c2);Student s = new Student();Class c3 = s.getClass();System.out.println(c3 == c2);}
}
public class Student {private String name;private int age;private char sex;private double height;private String hobby;public Student() {}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;}//省略getter、setter
}
2、获取类的构造器
使用反射技术获取构造器对象并使用
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
- Class类中用于获取构造器的方法:
- 获取构造器的作用依然是初始化一个对象返回。
- Constructor类中用于创建对象的方法:
/*** 获取类的构造器,并对其进行操作。*/
public class Test2Constructor {@Testpublic void testGetConstructors(){// 1、反射第一步:必须先得到这个类的Class对象Class c = Cat.class;// 2、获取类的全部构造器// Constructor[] constructors = c.getConstructors();Constructor[] constructors = c.getDeclaredConstructors();// 3、遍历数组中的每个构造器对象for (Constructor constructor : constructors) {System.out.println(constructor.getName() + "--->"+ constructor.getParameterCount());}}@Testpublic void testGetConstructor() throws Exception {// 1、反射第一步:必须先得到这个类的Class对象Class c = Cat.class;// 2、获取类的某个构造器:无参数构造器Constructor constructor1 = c.getDeclaredConstructor();System.out.println(constructor1.getName() + "--->"+ constructor1.getParameterCount());constructor1.setAccessible(true); // 禁止检查访问权限Cat cat = (Cat) constructor1.newInstance();System.out.println(cat);// 3、获取有参数构造器Constructor constructor2 =c.getDeclaredConstructor(String.class, int.class);System.out.println(constructor2.getName() + "--->"+ constructor2.getParameterCount());constructor2.setAccessible(true); // 禁止检查访问权限Cat cat2 = (Cat) constructor2.newInstance("叮当猫", 3);System.out.println(cat2);}
}
public class Cat {public static int a;public static final String COUNTRY = "中国";private String name;private int age;public Cat(){System.out.println("无参数构造器执行了~~");}private Cat(String name, int age) {System.out.println("有参数构造器执行了~~");this.name = name;this.age = age;}private void run(){System.out.println("🐱跑的贼快~~");}public void eat(){System.out.println("🐱爱吃猫粮~");}private String eat(String name){return "🐱最爱吃:" + name;}省略getter、setter、toString
}
3、获取类的成员变量
使用反射技术获取成员变量对象并使用
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
- Class类中用于获取成员变量的方法
- 获取成员变量的作用依然是在某个对象中取值、赋值
/*** 获取类的成员变量,并对其进行操作。*/
public class Test3Field {@Testpublic void testGetFields() 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());}// 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());// 赋值Cat cat = new Cat();fName.setAccessible(true); // 禁止访问控制权限fName.set(cat, "卡菲猫");System.out.println(cat);// 取值String name = (String) fName.get(cat);System.out.println(name);}
}
4、获取类的成员方法
使用反射技术获取方法对象并使用
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取成员方法的方法:
- 获取成员方法的作用依然是在某个对象中进行执行此方法
Method类中用于触发执行的方法:
/*** 获取类的成员方法,并对其进行操作。*/
public class Test4Method {@Testpublic void testGetMethods() 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());}// 4、获取某个方法对象Method run = c.getDeclaredMethod("run"); // 拿run方法,无参数的System.out.println(run.getName() + "--->"+ run.getParameterCount() + "---->"+ run.getReturnType());Method eat = c.getDeclaredMethod("eat", String.class);System.out.println(eat.getName() + "--->"+ eat.getParameterCount() + "---->"+ eat.getReturnType());Cat cat = new Cat();run.setAccessible(true); // 禁止检查访问权限Object rs = run.invoke(cat); // 调用无参数的run方法,用cat对象触发调用的。System.out.println(rs);eat.setAccessible(true); // 禁止检查访问权限String rs2 = (String) eat.invoke(cat, "鱼儿");System.out.println(rs2);}
}
5、作用、应用场景
- 需求:给定任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去。
public class Test5Frame {@Testpublic void save() throws Exception {Student s1 = new Student("张三", 45, '男', 185.3, "蓝球,冰球,阅读");Teacher t1 = new Teacher("李四", 999.9);// 需求:把任意对象的字段名和其对应的值等信息,保存到文件中去。ObjectFrame.saveObject(s1);ObjectFrame.saveObject(t1);}
}
public class Teacher {private String name;private double salary;public Teacher() {}public Teacher(String name, double salary) {this.name = name;this.salary = salary;}//省略getter、setter等
}
public class ObjectFrame {// 目标:保存任意对象的字段和其数据到文件中去public static void saveObject(Object obj) throws Exception {PrintStream ps = new PrintStream(new FileOutputStream("junit-reflect-app\\src\\data.txt", true));// obj是任意对象,到底有多少个字段要保存。Class c = obj.getClass();String cName = c.getSimpleName();ps.println("---------------" + cName + "------------------------");// 2、从这个类中提取它的全部成员变量Field[] fields = c.getDeclaredFields();// 3、遍历每个成员变量。for (Field field : fields) {// 4、拿到成员变量的名字String name = field.getName();// 5、拿到这个成员变量在对象中的数据。field.setAccessible(true); // 禁止检查访问控制String value = field.get(obj) + "";ps.println(name + "=" + value);}ps.close();}
}