文章目录
Junit单元测试
白盒测试
- 定义一个测试类(测试用例,测试类名:测试类Test,包名:…test)
- 定义测试方法:可以独立运行
- 给方法加注解@test
- 导入Junit
package cn.itcast.junit;
import org.junit.Assert;
import org.junit.Test;
public class CaculatorTest {
@Test
public void testAdd(){
Caculator c = new Caculator();
int result = c.add(1, 2);
Assert.assertEquals(3, result);
}
}
@Before初始化方法,用于资源申请,所有测试方法在执行之前都会先执行该方法
@After释放资源方法,在所有测试完之后执行该方法
反射
框架设计的灵魂
将类的各个组成部分封装成其他对象
好处
- 可以在程序运行过程中操作这些对象
- 可以解耦,提高程序的可扩展性
Class对象的功能:
获取功能:
获取Class对象的方式
- Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象多用于配置文件,将类名定义在配置文件中。读取文件,加载类
- 类名.class:通过类名的属性class获取多用于参数的传递
- 对象.getClass():getClass()方法在Object类中定义多用于对象的获取字节码的方式
- 结论:同一个字节码文件在第一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的class对象都是同一个
获取成员变量们
Field[]getFields
Field getField(String name)
Field[] getDeclaredFields()
Field getDeclaredField(String name)
获取构造方法们
Constructor<?>[] getConstructors()
Constructor<T> getConstructor(类<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()
获取成员方法
Method[] getMethods()
Method getMethod(String name, 类<?>... parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
获取类名
String getName()
忽略访问权限修饰符的安全检查
setAccessible(true)
暴力反射
通过构造方法创建对象
- 创建对象:T newInstance(Object… initargs)
Method:方法对象
- 执行方法:Object invoke(Object obj, Object… args)
- 获取方法名称: String getName:获取方法名
package cn.itcast.reflect;
import cn.itcast.domain.Person;
import java.lang.reflect.Method;
public class Reflect2 {
public static void main(String[] args) throws Exception {
Class personClass = Person.class;
// Field[] fields = personClass.getFields();
// for (Field field : fields) {
// System.out.println(field);
// }
// System.out.println("--------------");
// Field a = personClass.getField("a");
// Person p = new Person();
// a.set(p, 32);
// System.out.println(a.get(p));
// System.out.println("=============");
// Field[] declaredField = personClass.getDeclaredFields();
// for (Field field : declaredField) {
// System.out.println(field);
// }
// Constructor constructor = personClass.getConstructor(String.class, int.class);
// System.out.println(constructor);
// Object person = constructor.newInstance("张三", 23);
// System.out.println(person);
// System.out.println("------------");
// Constructor constructor1 = personClass.getConstructor();
// System.out.println(constructor1);
// Object person2 = constructor1.newInstance();
// System.out.println(person2);
Method eat_method = personClass.getMethod("eat");
Person p = new Person();
eat_method.invoke(p);
Method eat_method2 = personClass.getMethod("eat", String.class);
eat_method2.invoke(p, "rice");
System.out.println("---------");
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
实例
实现
- 配置文件
- 反射
步骤
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 在程序中加载读取配置文件
- 使用反射技术来加载类文件进内存
- 创建对象
- 执行方法
配置文件
className = package cn.itcast.domain.Person
methodName = eat
反射
package cn.itcast.reflect;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectClass {
public static void main(String[] args) throws Exception{
//可以创建任意类的对象,可以执行任意方法
/*Person p = new Person();
p.eat();*/
Properties pro = new Properties();
//获取class目录下的配置文件
ClassLoader classLoader = ReflectClass.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//加载该类进内存
Class cls = Class.forName(className);
//创建对象
Object obj = cls.newInstance();
//获取方法对象
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}
注解
作用分类
- 编写文档:通过代码里标识的注解生成文档【生成doc文档】
- 代码分析: 通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查: 通过代码里标识的注解能让编译器能够实现基本的编译检查【Override】
JDK中预定义的注解
- @Override
- @Deprecared
- @SuppressWarnings
自定义注解
格式:
- 元注解
- public @interface 注解名称{}
本质:
- 本质上就是接口,继承于Annotation接口
属性:接口中可以定义的成员方法
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
- 定义了属性,在使用时需要给属性赋值
元注解
- @Target:描述能够作用的位置
- @Retention: 描述注解被保留的阶段
- @Documented: 描述注解是否被抽取到api
- @Inherited: 描述注解能否被子类继承
在程序中使用注解
- 获取注解定义的位置对象
- 获取指定的注解
getAnnotation(class)
//其实就是在内存中生成了一个该注解接口的子类实现对象
package cn.itcast.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
String className();
String methodName();
}
public class ProImpl implements Pro{
public String className(){
return "cn.itcast.annotation.Demo1";
}
public String methodName(){
return "show";
}
}
- 调用注解中的抽象方法获取配置的属性值
package cn.itcast.annotation;
import java.lang.reflect.Method;
@Pro(className = "cn.itcast.annotation.Demo1", methodName = "show")
public class ReflectTest {
public static void main(String[] args) throws Exception{
//解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//其实就是在内存中生成了一个该注解接口的子类实现对象
Pro an = reflectTestClass.getAnnotation(Pro.class);
String className = an.className();
String methodName = an.methodName();
System.out.println(className);
System.out.println(methodName);
Class cls = Class.forName(className);
Object object = cls.newInstance();
Method method = cls.getMethod(methodName);
method.invoke(object);
}
}
实例
注解
package cn.itcast.annotation.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}
类
package cn.itcast.annotation.demo;
public class Calculator {
@Check
public void add() {
System.out.println("1 + 0 =" + (1 + 0));
}
@Check
public void sub() {
System.out.println("1 - 0 =" + (1 - 0));
}
@Check
public void mul() {
System.out.println("1 * 0 =" + (1 * 0));
}
@Check
public void div() {
System.out.println("1 / 0 =" + (1 / 0));
}
@Check
public void show() {
System.out.println("永无bug ...");
}
}
测试类
package cn.itcast.annotation.demo;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* 简单的测试框架
* 当主方法执行后,会自动执行被检测的所有方法(加了check注解的方法),判断方法是否有异常,记录到文件中
*/
public class TestCheck {
public static void main(String[] args) throws IOException {
//创建计算机对象
Calculator c = new Calculator();
//获取字节码文件对象
Class cls = c.getClass();
//获取所有方法
Method[] methods = cls.getMethods();
int number = 0;
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
if (method.isAnnotationPresent(Check.class)) {
try {
method.invoke(c);
} catch (Exception e) {
number ++;
bw.write(method.getName() + " 方法出现了异常");
bw.newLine();
bw.write("异常的名称" + e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因" + e.getCause().getMessage());
bw.newLine();
}
}
}
bw.write("本次测试一共出现" + number + " 次异常");
bw.flush();
bw.close();
}
}
生成的bug.txt
div 方法出现了异常
异常的名称ArithmeticException
异常的原因/ by zero
本次测试一共出现1 次异常