单元测试
- 就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试
Junit单元测试框架
- 可以用来对方法进行测试,它是第三方公司开源出来的(很多开发工具已经继承了Junit框架,比如IDEA)
优点:
- 可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。
- 不需要程序员去分析测试的结果,会自动生成测试报告出来。
具体步骤
- 将unit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不要我们自己手工导入了)
- 为需要测试的业务类,定义对应的测试类,并为每个业务方法,编写对应的测试方法(必须:公共、无参、无返回值)
- 测试方法上必须声明@Test注解,然后在测试方法中,编写代码调用被测试的业务方法进行测试
- 开始测试:选中测试方法,右键选择“Junit运行”,如果测试通过,则是绿色;如果测试失败,则是红色
Junit单元测试框架的日常注解 Junit4
注解 | 说明 |
@Test | 测试类中的方法必须用它修饰才能成为测试方法,才能启动执行 |
@Before | 用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次 |
@After | 用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次 |
@BeforeClass | 用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次 |
@AfterClass | 用来修饰一个静态方法,该方法会在所有测试方法之后执行一次 |
- 在测试方法执行前执行的方法,常用于:初始化资源
- 在测试方法执行完成后再执行的方法,常用于:释放资源
Junit单元测试框架的日常注解 Junit5
注解 | 说明 |
@Test | 测试类中的方法必须用它修饰才能成为测试方法,才能启动执行 |
@BeforeEach | 用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次 |
@AfterEach | 用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次 |
@BeforeAll | 用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次 |
@AfterAll | 用来修饰一个静态方法,该方法会在所有测试方法之后执行一次 |
- 开始执行的方法:初始化资源
- 执行完之后的方法:释放资源
反射(Reflection)
反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。
Class提供了从类中获取构造器的方法
方法 | 说明 |
Constructor<?> getConstructors() | 获取全部构造器(只能获取public修饰的) |
Constructor<?> getDeclaredConstructors() | 获取全部构造器(只要存在就能拿到) |
Constructor<T> getConstructor(Class<?>...parameterTypes) | 获取某个构造器(只能获取public修饰的) |
Constructor<T> getDeclaredconstructor(class<?>... parameterTypes) | 获取某个构造器(只要存在就能拿到 |
获取类构造器的作用:依然是初始化对象返回
Constructor提供的方法 | 说明 |
T new Instance(object... initargs) | 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
Class提供了从类中获取成员变量的方法
方法 | 说明 |
public Field[] getFields() | 获取类的全部成员变量(只能获取public修饰符的) |
public Field[] getDeclaredFields() | 获取类的全部成员变量(只要存在就能获取) |
public Field getField(String name) | 获取类的某个成员变量(只能获取public修饰符的) |
public Field getDeclaredField(String name) | 获取类的某个成员变量(只要存在就能获取) |
获取到成员变量的作用:依然是赋值、取值
方法 | 说明 |
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 赋值 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
Class提供了从类中获取成员方法的API
方法 | 说明 |
public Field[] getMethods() | 获取类的全部成员方法(只能获取public修饰符的) |
public Field[] getDeclaredMethods() | 获取类的全部成员方法(只要存在就能获取) |
public Field getMethod(String name, class<?>... parameterTypes) | 获取类的某个成员方法(只能获取public修饰符的) |
public Field getDeclaredMethod(String name, class<?>... parameterTypes) | 获取类的某个成员方法(只要存在就能获取) |
成员方法的作用:执行
Method提供的方法 | 说明 |
public Object invoke(Object obj, Object ... args) | 触发某个成员方法执行 |
public void setAccessible(boolean flag) | 设置为true,表示禁止检查访问控制(暴力反射) |
反射的作用
- 基本作用:可以得到一个类的全部成分然后操作
- 可以破坏封装性
- 最重要的用途是:适合做Java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能
需求:
- 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去。
实现步骤
- 定义一个方法,可以接收任意对象
- 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
- 遍历成员变量,然后提取成员变量在该对象中的具体值
- 把成员变量名和其值,写出到文件中去即可
// Student
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;
}
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;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
// Teacher
public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}
public Teacher() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
// ObjectFrame
public static void saveObject(Object obj) {
// 创建文件打印流 在@Test测试执行下必须写绝对路径 否则报错 找不到文件
try (PrintStream ps = new PrintStream(new FileOutputStream("F:\\F盘资料\\学习web\\java\\1\\javasepromax\\day22" +
"-junit-annotation-proxy-app\\src\\data.txt",
true));) {
// obj任意对象
Class c = obj.getClass();
// 获取类名
String className = c.getSimpleName();
ps.println("-------------------------------------" + className +
"----------------------------------------------");
// 从这个类中获取成员变量
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
// 拿到成员变量
String name = field.getName();
// 强制反射
field.setAccessible(true);
// 拿到成员变量数据
String value = field.get(obj) + "";
//输出数据到文件
ps.println(name + "=" + value);
}
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//main
public class Test5Frame {
@Test
public void save() throws Exception {
Student s1 = new Student("刘亦菲", 30, '女', 165, "演员");
Teacher t1 = new Teacher("波妞", 9999.9);
// 使用框架
ObjectFrame.saveObject(s1);
ObjectFrame.saveObject(t1);
}
}
注解(Annotation)
- 就是Java代码里的特殊标记,比如:@Override、@Test等,作用是:让其他程序根据注解信息来决定怎么执行该程序。
- 注意:注解可以用在类上、构造器上、方法上、成员变量上、参数上等位置处
自定义注解
就是自己定义注解
public @interface 注解名称{
public 属性类型 属性名() default 默认值;
}
特殊属性名:value
- 如果注解中只有一个value属性,使用注解时,value名称可以不写!
@MyTest1(aaa="小仙女", ccc={ "html", "Java"})
public class Annotation {
@MyTest1(aaa="小姐姐", bbb = false, ccc={"Python", "前端", "Java"})
public void test1(){
}
// @MyTest2("孙悟空") // 只有value
// @MyTest2(value = "孙悟空", age= 800) // 有value和age两个 age没有默认值
@MyTest2("孙悟空") // 有value和age age有默认值
public void test2(){}
}
// MyTest1
public @interface MyTest1 {
String aaa();
boolean bbb() default true;
String[] ccc();
}
//MyTest2
public @interface MyTest2 {
String value();
// int age();
int age() default 21;
}
- 注解本质是一个接口,Java中所有注解都是继承了Annotation接口的。
- @注解(...):其实就是一个实现类对象,实现了该注解以及Annotation接口。
元注解
修饰注解的注解
@Target
作用:声明被修饰的注解只能在哪些位置使用
@Target(ElementType.Type)
- TYPE,类,接口
- FILED,成员变量
- METHOD,成员方法
- PARAMETER,方法参数
- CONSTRUCTOR,构造器
- LOCAL_VARIABLE,局部变量
@Retention
作用:声明注解的保留周期
@Retention(RetentionPolicy.RUNTIME)
SOURCE
- 只作用在源码阶段,字节码文件中不存在
CLASS(默认值)
- 保留字节码文件阶段,运行阶段不存在
RUNTIME(开发常用)
- 一直保留到运行阶段
注解的解析
判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来
如何解析注解?
- 指导思想:要解析上面的注解,就应该先拿到谁。
- 比如要解析类上面的注解,则应该先获取该类的Class对象,在通过Class对象解析其上面的注解
- 比如要解析成员方法上的注解,则应该获取到该成员方法的method对象,在通过Method对象解析其上面的注解
- Class、Method、Field、Contructor都实现了AnnotatedElement接口,他们都拥有解析注解的能力
AnnotatedElement接口提供了解析注解的方法 | 方法 |
public Annotation[] getDeclaredAnnotations() | 获取当前对象上面的注解 |
public T getDeclaredAnnotation(Class<T> annotationClass) | 获取指定的注解对象 |
public boolean isAnnotationPresent(Class<Annotation> annotationClass) | 判断当前对象上是否存在某个注解 |