Junit单元测试与反射
黑盒-白盒
junit使用:白盒测试
步骤:
- 定义一个测试类
- 测试类名:被测试类+Test
CalculatorTest
- 包名:xxx.xxx.xxx.test
- 测试类名:被测试类+Test
- 定义测试方法:可以独立执行,建议
- 方法名:test测试方法名
testAdd()
- 返回值:void(独立运行)
- 参数列表:空参
- 方法名:test测试方法名
- 方法+@test注解
- 导入Junit依赖环境
1 | package test; |
1 | package junit; |
在add添加除0异常
1 | package junit; |
假设原方法中add写成了-,使用断言报错
1 | package test; |
同理可以得到sub的测试函数
1 | //测试sub方法 |
注解补充
@Before
-
初始化方法
-
用于资源的申请,所有测试方法执行之前都会先执行该方法
-
在测试方法之前被自动执行
@After
-
释放资源
-
在所有测试方法执行完后都会自动执行该方法
-
测试方法执行之后自动执行
1 | //初始化方法 |
反射
框架设计的灵魂
框架:半成品软件。可以在框架基础上继续开发,简化编码
反射:将类的各个组成部分封装为其他对象(反射机制)
- 好处:
- 在程序运行中操作这些对象
- 可以解耦,提高程序可拓展性
Java代码运行阶段
获取Class对象方式
-
Source:
对用于配置文件,将类名定义在配置文件中。读取文件,加载类
Class.forName(“全类名”):将字节码文件加载进内存返回class对象
-
Class:
多用于参数传递
依据类名属性class,获取class对象
-
Runtime
多用于对象的获取字节码的方式
对象.getClass():方法封装在Object中,被所有对象继承了
同一个字节码文件在同一次程序运行中,只会被加载一次;不论通过那种方式取得,都是同一个对象
每个类对象都不同
使用class对象
功能:
-
获取:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47package LearnJunit.domain;
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
}-
获取成员变量们
-
Field[] getFields()
:获取所有public成员变量1
2
3
4Field[] fields = personClass.getFields();
for (Field field: fields){
System.out.println(field);
} -
Field getField(String name)
:获取所有指定名称public成员变量1
Field a = personClass.getField("a");
-
Field[] getDeclaredFields()
1
2
3
4
5//获取所有成员变量,不考虑修饰
Field[] DeclaredFields = personClass.getDeclaredFields();
for (Field getDeclaredField: DeclaredFields){
System.out.println(getDeclaredField);
} -
Field getDeclaredField(String name)
反射私有、保护成员变量,要设置忽略访问权限的修饰符安全监测
1
2
3
4
5
6
7//1.4获取单个私有
System.out.println("---------------");
Field d = personClass.getDeclaredField("d");
//1.4.1忽略安全访问
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);
-
-
获取构造方法们
-
Constructor<?>[] getConstructors()
1
2Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor); -
Constructor<T> getConstructor(String name)
-
Constructor<?>[] getDeclaredConstructors()
-
Constructor<T> getDeclaredConstructor(String name)
-
-
获取成员方法们
-
method[] getMethods()
1
2
3
4
5//获取所有public修饰方法
Method[] funcs = personClass.getMethods();
for (Method func:funcs){
System.out.println(func);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public java.lang.String LearnJunit.domain.Person.toString()
public java.lang.String LearnJunit.domain.Person.getName()
public void LearnJunit.domain.Person.setName(java.lang.String)
public int LearnJunit.domain.Person.getAge()
public void LearnJunit.domain.Person.setAge(int)
public void LearnJunit.domain.Person.eat()
public void LearnJunit.domain.Person.eat(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()因为Person类继承的是Object对象,所以有些隐藏函数,即从Object继承下来的函数
-
method getMethod(String name)
1
2
3
4
5//获取指定方法名称
//名字,参数列表匹配
Method eat = personClass.getMethod("eat");
Method eat2 = personClass.getMethod("eat",String.class);
eat2.invoke(p,"fish"); -
method[] getDeclaredMethods()
-
method getDeclaredMethod(String name)
-
-
获取类名
String getName()
-
-
操作
-
Field成员变量
设置值(get)
1
2
3
4
5Field a = personClass.getField("a");
//获取成员变量a的值
Person p = new Person();
Object value = a.get(p);
System.out.println(value);获取值(set)
1
2a.set(p,"John");
System.out.println(p); -
暴力反射:
.setAccessible(true);
对所有反射都有效搭配
getDeaclearedXXX
使用这仅仅是打印名称和比较,不需要设置;但是如果要对对象进行相关操作,必须设置;不设置的话操作受限。
-
Constructor构造方法
创建对象
T newInstance(Object... initargs)
1
2
3//1.2创建对象
Object person = constructor.newInstance("Jonh",5);
System.out.println(person);如果构造使用空参创造对象,可简化 class对象的
newInstance
1
2
3Object o = personClass.newInstance();
System.out.println(o);
System.out.println("-------------"); -
Method成员对象
执行方法
1
2
3
4
5
6//获取指定方法名称
Method eat = personClass.getMethod("eat");
//创建方法对象
Person p = new Person();
//执行方法
eat.invoke(p);获取方法名称
1
System.out.println(func.getName());
-
获取类名
1
2
3//获取类名
String classname = personClass.getName();
System.out.println(classname);
-
反射案例
案例:
需求:一个框架,可以帮我们创建任意类的对象,并且执行任意方法
不能改变该类的任何代码,
创建任意对象执行任意方法
一般方式:
1 | package LearnJunit.reflect; |
这里的框架是提前学好的,不能改变;若要使用student类,则代码会改变
实现
- 配置文件
- 反射
步骤
-
将需要创建的对象的全类名和需要执行的方法定义在配置文件中
src中创建配置文件
1
2className=LearnJunit.domain.Person
methodName=eat -
在程序中加载读取配置文件
1
2
3
4
5
6
7
8
9
10
11//1.加载配置文件
//1.1创建配置对象
Properties pro = new Properties();
//1.2加载配置文件,转换为集合
//1.2.1获取class目录下配置文件
ClassLoader classLoader = ReflectFramework.class.getClassLoader();//获得当前类路径
InputStream is = classLoader.getResourceAsStream("config.properties");//读取路径下的config.properties
pro.load(is);
//2.获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName"); -
使用反射技术来加载类文件进内存,创建对象并执行方法
1
2
3
4
5
6
7//3.加载类进内存
Class cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
method.invoke(obj);
完整代码
1 | package LearnJunit.reflect; |
这样只需要修改配置文件就可以了