Junit
1什么是Junit测试:是白盒测试的一种(白盒测试更高级一些)

2怎么使用Junit类:
1先定义一个测试类:


代码:
:
2运行测试类:

代码:注意@Test后要添加依赖(这里我们测试的是类中的减法)

3查看判定结果(断言):使用assertEquals方法,用断言结果和实际结果进行比较
![]()
结果为绿色就是成功

结果为红色就是失败

4补充知识点:@Before和@After,无论测试是否出现异响都会执行
@Before修饰的方法会在所有测试方法之前执行,通常用来申请资源
@After修饰的方法会在所有测试方法之前执行,通常用来释放资源
反射
1什么是反射:反射是对类的属性(成员变量,构造方法,成员方法)的封装,每个部分通过类加载器分别封装成为fields,constructor,method这些class对象,方便我们从内存中对这些方法进行使用。反射是框架设计的灵魂。

String字符串所能调用的这些个方法,都是之前封装好,存在java的method类对象中的,当我们.出这些方法的时候,就启用了反射机制。

2获取字节码Class对象的三种方式

package com.bed.java.Junit.reflect;
//使用三种方式来导出class文件
public class ReflectDemo01 {
public static void main(String[] args) throws Exception {
//第一种方式:直接用class静态方法查看类对象
Class aClass = Class.forName("com.bed.java.Junit.reflect.Person");
System.out.println(aClass);
//第二种方式,通过类名导出class对象
Class aClass1 = Person.class;
System.out.println(aClass1);
//第三种方式通过对象来获取class对象
Person p=new Person();
Class aClass2 = p.getClass();
System.out.println(aClass2);
System.out.println(aClass==aClass1);
System.out.println(aClass==aClass2);
}
}
最后两行为了证明,不论用哪种方式获取,同一个类的.class文件的地址是不变的
3class对象的功能
1.获取成员变量:获取所有成员变量.getfields
获取指定成员变量.getfield("指定名称")
Class<Person> personClass = Person.class;
//获取Person对象的所有public变量
Field[] fields = personClass.getFields();
for (Field field : fields) {
/*遍历显示的结果只有a成员变量,因为a是public修饰的,
除了public修饰的,其他作用域都不行*/
System.out.println(field);
}
//获取Person对象的指定public变量
Field a = personClass.getField("a");
Person p=new Person();
注意:获取的只能是public修饰的成员变量
那为了获取所有的成员变量,我们可以使用getDeclaredFields方法:
//使用getDeclaredFields();方法来获取所有(public-private)成员变量
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
}
2获取成员变量的值,给成员变量赋值:get/set
//获取Person对象的指定public变量
Field a = personClass.getField("a");
Person p=new Person();
//使用field获取成员变量的值:这个步骤与平常相反,是用成员变量a,
// 传递a所在的类Person的对象p进去,来获取a成员变量在Person类里面的值
Object o = a.get(p);
System.out.println(o);//null
//设置成员变量a的值
a.set(p,"bed");
System.out.println(p);//Person{name='null', age=0, a='bed'}
如果该成员变量为私有成员变量,可以使用:getDeclaredField("name"),来获取任何指定
成员变量,如果要对私有变量进行读取或者设定,要使用setAccessible(true)方法;
这一步通常称为:忽略访问权限的安全检查(暴力反射)
//获取Person对象的指定private变量
Field name = personClass.getDeclaredField("name");//获取Person中的name私有成员变量
name.setAccessible(true);//忽略访问权限的安全检查(暴力反射)
Object o1 = name.get(p);
System.out.println(o1);
3获取类的构造方法:获取空参构造对象,获取有参构造对象
package com.bed.java.Junit.reflect;
import java.lang.reflect.Constructor;
public class Demo03Constructor {
public static void main(String[] args) throws Exception {
Person p=new Person();
Class pClass = p.getClass();//获取类对象
//获取类的构造器(空参)
Object person = pClass.newInstance();
//获取类的构造器(有参):构造方法是按照构造参数来区分的,所以输入构造参数的类型来找构造方法
//Person对象的有参构造方法一个是String类型的name 一个是int类型的age
Constructor constructor = pClass.getConstructor(String.class, int.class);//获取构造器
System.out.println(constructor);
//使用构造器来创建对象,调用构造器的newInstance方法来创建Person对象
Object person1 = constructor.newInstance("bed", 23);
System.out.println(person1);
}
}
getDeclaredConstructor的使用方法同Field对象相同,在此不做赘述
4获取类的成员方法:getMethod(方法三要素)
package com.bed.java.Junit.reflect;
import java.lang.reflect.Method;
public class Demo04Method {
public static void main(String[] args) throws Exception {
Person p=new Person();
Class pClass = p.getClass();
//里面可以传入三个参数1方法名称2方法返回值3成员方法需要的参数
//也就是方法的三要素
Method eat = pClass.getMethod("eat", String.class);//这里传入方法名称和方法参数
//参数传入Person对象和成员方法需要的参数,然后调用invoke执行方法
eat.invoke(p, "汉堡");
}
}
注意:1、如果要查看所有成员方法getMethods,里面显示的结果会有一些隐藏方法,
也就是Object类的成员方法
2、getDeclaredMethods使用与Field相同。
3、获取Method对象后也可以用.getName再去返回获得成员方法名称(来回折腾)
练习:使用配置文件和反射,实现通过配置外部txt文件,来显示不同类中的不同方法
1:首先先了解什么是配置文件,可以通俗的理解为,通过对一个文件(txt格式)内容的
操纵,来实现运行结果的改变。注意:本案例中这个文件是用来控制类文件的,新建的
时候要与.class文件平级,也就是和src在同一级。

2使用配置文件:在配置文件中我们要存储两个变量,1 类名称 2 类方法。存储的形式我们
使用Properties(因为是在txt文件里)。注意:类名称要写绝对路径

3代码实现
package com.bed.java.Junit.reflect;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
//在不动源代码的前提下,实现两个类的方法由操作者自由切换
public class Demo05PeiZhiWenJian {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//创建一个Properties集合,用来接收类名称和类方法,这里我们把类基础属性作为键,类的真实名称为值
Properties pro=new Properties();
FileReader fr=new FileReader("D:\\study\\high level code\\day10-code test\\class.txt");//新建一个配置文件的读取路径
pro.load(fr);//资源通过路径开始加载
fr.close();//关闭流
//通过txt文档中classname和classmethodname两个键,获取当前的对应值
String className = pro.getProperty("className");
String classmethodname = pro.getProperty("classmethodname");
//使用反射来执行方法
//1、创建一个类对象,参数传递上面获得的类名称
Class<?> classname1 = Class.forName(className);
//获取该类的成员方法,参数传递上面获得的类方法名称
Method method = classname1.getMethod(classmethodname);
//获取该类的无参构造方法
Constructor<?> constructor = classname1.getConstructor();
//通过获得的构造方法来创建一个对象
Object o = constructor.newInstance();
//执行方法
method.invoke(o);
}
}
注解:
1、什么是注解:api里的说明,@overide @functionalinterface 这些都是注解。
2、注解的作用:

1里面所说的是自己制作一个index说明文档,如下图,先手动在代码里面写好注解

然后用cmd 去运行拿出来的这个类AnnoDemo01

出现如下结果

3 jdk中自定义的一些注解:
1 、 ![]()
2 、functionalinterface:判断是否为函数式接口
3、![]()
举例,当你想用新的show02方法代替show01方法而又不想删除老方法时

4、![]()
注意图中红圈部分就是java自动提示的一些警告,此时没有压制警告
使用@SuppressWarnings压制警告,将此注解写在类名称前面,写上all,所有黄色条条消失

4注解的本质:本质上就是一种Annotation接口,接口里面的抽象方法就叫做注解的属性
5如何自定义注解:注解格式如下

注解的属性可以是如下种类:
如果我们顶定义了注解属性,接下来在使用注解的时候就要给注解赋值,需要注意如下几点

举例:同时使用 1基本数据类型2枚举3注解4字符组 作为属性的自定义注解

6注解的元注解:也就是解释注解的注解,通常写在注解接口上面,里面通常有四要素

1Target:大括号里面传递字符串组,用来限定该注解可用在哪里,如下图所示,说明:
该注解可以用在(TYPE类,FILED成员变量,METHOD成员方法)上

2Retention:解释当前注解保留在哪个阶段,通常我们都会定义在RUNITIME这个阶段。
![]()
3Documented:让当前注解可以出现在api文档上
4Inherited :子类继承父类注解
实例:用注解来替代配置文件。其中的关键点:如何获取注解接口中的属性(方法)
package com.bed.java.Junit.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/*用注解来代替配置文件*/
//我们在注解中写好注解中需要的两参数的数据
@Peizhiwenjian(classname = "com.bed.java.Junit.Annotation.eat",methodname = "chifan")
public class AnnoReflect {
public static void main(String[] args) throws Exception {
//第一步,把注解中的参数数据拿到主程序中(解析注解)
//1.1先获取当前类的字节码对象
Class<AnnoReflect> annoReflectClass = AnnoReflect.class;
//用字节码对象获取当前类的注解对象(参数传递你想要的那个注解)
//注意这个anno 是一个接口的子类实现类
Peizhiwenjian anno = annoReflectClass.getAnnotation(Peizhiwenjian.class);
//用注解对象获取当前注解的属性(就是注解的抽象方法)
//此时的返回值就是最上面注解的配置值
String classname = anno.classname();//com.bed.java.Junit.Annotation.eat
String methodname = anno.methodname();//chifan
System.out.println(classname);
//使用反射来执行方法
//1、创建一个类对象,参数传递上面获得的类名称
Class<?> classname1 = Class.forName(classname);
//获取该类的成员方法,参数传递上面获得的类方法名称
Method method = classname1.getMethod(methodname);
//获取该类的无参构造方法
Constructor<?> constructor = classname1.getConstructor();
//通过获得的构造方法来创建一个对象
Object o = constructor.newInstance();
//执行方法
method.invoke(o);
}
}
实例 2 自定义注解来实现:类中共有4个成员方法 要分别查出4个成员方法是否都正常运行了
(注意 还要新创建一个错误日志 用来接收错误信息)注意:错误日志的抓取就是在invoke
关键字出现时,catch自动抓取的Exception可以自定义。后续的bug细致分析用
get.class get.massage get.cause get.simplename即可(不懂看视频吧)
测试类
package com.bed.java.Junit.Annotation.CalcTest;
//定义一个计算器类,里面有四个成员方法,检查这四个方法是否能正常执行
public class Calculator {
@Check
public void add(){
int num=1/0;
System.out.println("1+0="+(1+0));
}
@Check
public void sub(){
System.out.println("1-0="+(1-0));
}
@Check
public void mult(){
System.out.println("1*0="+1*0);
}
@Check
public void div(){
System.out.println("1/0="+1/0);
}
public void noPro(){
System.out.println("no problem");
}
}
注解接口
package com.bed.java.Junit.Annotation.CalcTest;
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 com.bed.java.Junit.Annotation.CalcTest;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class CalcTest {
public static void main(String[] args) throws IOException {
//第一步,建立一个txt文档用来记录bug
int num=0;//这个是用来记录bug出现的次数
BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt"));
//第二步,我们要把Calculator中的所有成员方法都找出来
//判断该方法有没有Check注解
//1、获取Calculator字节码文件对象
Class<Calculator> calculatorClass = Calculator.class;
//2、获取字节码文件的所有方法
Method[] methods = calculatorClass.getMethods();
//3、将获得的方法组来遍历
for (Method method : methods) {
//看看每一条是否有注解
if (method.isAnnotationPresent(Check.class)){
//如果有Check注解,就执行该方法,此时invoke会出现异常,这个异常就是运行时期的异常
//我们使用trycatch来捕获异常,并记录到日志中
try {
method.invoke(new Calculator());
} catch (Exception e) {//捕获异常并记录到日志,此处是自定义的catchException
num++;//每有一个bug就+1
bw.write("出现bug的方法名称:"+method.getName());
bw.newLine();//换行
//获取异常的简短类名
bw.write("该异常名为:"+e.getCause().getClass().getSimpleName());
bw.newLine();//换行
bw.write("异常的原因:"+e.getCause().getMessage());
bw.newLine();//换行
bw.write("=====================");
bw.newLine();//换行
}
}
}
bw.write("本次共出现异常次数:"+num);
bw.flush();
bw.close();
}
}
日志结果:
本文详细介绍了Java中的Junit测试,包括如何定义和运行测试类,使用断言,以及@Before和@After注解。接着讨论了反射的概念,如何获取和操作类的成员变量、构造方法和成员方法。还提到了通过配置文件和反射实现动态调用。此外,文章阐述了注解的基本概念、用途,以及如何自定义注解,包括注解的元注解和属性。最后,通过示例展示了如何利用注解进行方法运行状态的检查。
262

被折叠的 条评论
为什么被折叠?



