单元测试
1. 前言
- 单元测试是指程序员写的测试代码给自己的类中的方法进行预期正确性的验证。
- 单元测试一旦写好了这些测试代码,就可以一直使用,可以实现一定程度上的自动化测试。
- 单元测试一般要使用框架进行。
1.1 什么是框架?
框架是前人或者一些牛逼的技术公司在实战或者研发中设计的一些优良的设计方案或者成型的
代码功能,作为一个完整的技术体系发行出来称为框架。框架可以让程序员快速拥有一个强大的解决方案,可以快速的开发功能,提高效率并且直接就有了很好的性能。
单元测试的经典框架:Junit
1.2 Junit是什么
- Junit是Java语言编写的第三方单元测试框架(工具类)
- Junit框架的方案可以帮助我们方便且快速的测试我们的代码的正确性。
Junit单元测试框架的作用 - 用来对类中的方法功能进行有目的的测试,以保证程序的正确性和稳定性。
- 能够独立的测试某个方法或者所有方法的预期正确性。
1.3 Junit注解
- @Before // 修饰实例方法。在每个单元测试方法执行之前执行一次
- @After // 修饰实例方法。在每个单元测试方法执行之后执行一次
- @BeforeClass // 修饰静态方法。在每个单元测试方法执行之前执行一次
- @AfterClass // 修饰静态方法。在每个单元测试方法执行之后执行一次
- @Test
2. 概述
- 单元:在Java中,一个类就是一个单元
- 单元测试:程序猿用Junit编写的一小段代码,用来对某个类中的某个方法进行功能测试或业务逻辑测试。
3. 操作步骤
3.1 下载这个框架。(别人设计好的技术体系)
- 框架一般是jar包的形式,jar包里面都是class文件。
- class文件就是我们调用的核心代码。
- Junit已经被IDEA下载好了,可以直接导入到项目使用的。
3.2 直接用Junit测试代码即可
先模拟业务代码
-
写测试类
- 测试类的命名规范:以Test开头,以业务类类名结尾,使用驼峰命名法
- 业务名称是:UserService
- 测试这个业务类的测试类:TestUserService
-
在测试类中写测试方法
- 测试方法的命名规则:以test开头,以业务方法名结尾
比如被测试业务方法名为:login,那么测试方法名就应该叫:testLogin
- 测试方法的命名规则:以test开头,以业务方法名结尾
-
测试方法注意事项
- 必须是public修饰的,没有返回值,没有参数
- 必须使注解@Test修饰
3.3 如何运行测试方法
- 选中方法名 --> 右键 --> Run '测试方法名' 运行选中的测试方法
- 选中测试类类名 --> 右键 --> Run '测试类类名' 运行测试类中所有测试方法
- 选中模块名 --> 右键 --> Run 'All Tests' 运行模块中的所有测试类的所有测试方法
3.4 如何查看测试结果
绿色:表示测试通过
红色:表示测试失败,有问题
反射
1. 概述
1.1 反射
- 是Java的高级技术,是Java独有的技术。是Java技术显著的特点。
- 反射是指对于任何一个类,在运行的时候都可以直接得到这个类全部成分。
- 在运行时,可以直接得到这个类的构造器对象。(Constructor)
- 在运行时,可以直接得到这个类的成员变量。(Field)
- 在运行时,可以直接得到这个类的成员方法。(Method)
- 反射的核心思想和关键就是得到:编译以后的class文件对象。
1.2 小结:
- 反射必须工作在运行时。
- 反射的关键是得到编译以后的Class文件对象
- 反射可以在运行时得到一个类的全部成分进行一些操作。
2. 获取
2.1 类
-
反射技术的第一步永远是先得到Class类对象:有三种方式获取
- 类名.class
- 通过类的对象.getClass()方法
- Class.forName("类的全限名")
public static Class<?> forName(String className);
-
Class类下的方法
// 获得类名字符串:类名 String getSimpleName(); // 获得类全名:包名+类名 String getName(); // 创建Class对象关联类的对象 T newInstance() ;
2.2 构造器
-
反射中Class类型获取构造器提供了很多的API
// 根据参数匹配获取某个构造器,只能拿public修饰的构造器,几乎不用! Constructor getConstructor(Class... parameterTypes); // 根据参数匹配获取某个构造器,只要申明就可以定位,不关心权限修饰符,建议使用! Constructor getDeclaredConstructor(Class... parameterTypes); // 获取所有的构造器,只能拿public修饰的构造器。几乎不用!!太弱了! 3. Constructor[] getConstructors(); // 获取所有申明的构造器,只要你写我就能拿到,无所谓权限。建议使用!! 4. Constructor[] getDeclaredConstructors();
-
小结:
- 获取全部构造器,建议用getDeclaredConstructors();
- 获取某个构造器,建议用getDeclaredConstructor(Class... parameterTypes)
- 他们都无所谓权限,只要申明了就可以去取!!
- 反射是破环封装性的!!
2.3 成员变量
-
API
// 根据成员变量名获得对应Field对象,只能获得public修饰 Field getField(String name); // 根据成员变量名获得对应Field对象,只要申明了就可以得到 Field getDeclaredField(String name); // 获得所有的成员变量对应的Field对象,只能获得public的 Field[] getFields(); // 获得所有的成员变量对应的Field对象,只要申明了就可以得到 Field[] getDeclaredFields();
-
Field的方法:给成员变量赋值和取值
// 给对象注入某个成员变量数据 void set(Object obj, Object value); // 获取对象的成员变量的值 Object get(Object obj); // 暴力反射,设置为可以直接访问私有类型的属性 void setAccessible(true); // 获取属性的类型,返回Class对象 Class getType(); // 获取属性的名称 String getName();
2.4 方法
-
反射获取类的Method方法对象
// 根据方法名和参数类型获得对应的方法对象,只能获得public的 Method getMethod(String name,Class...args); // 根据方法名和参数类型获得对应的方法对象,包括private的 Method getDeclaredMethod(String name,Class...args); // 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的 Method[] getMethods(); // 获得类中的所有成员方法对象,返回数组,只获得本类申明的方法 Method[] getDeclaredMethods();
-
Method的方法
Object invoke(Object obj, Object... args)
- 触发的是哪个对象的方法执行。
- args:调用方法时传递的实例参数
3. 拓展:反射的作用
- 可以在运行时得到一个类的全部成分然后操作。
- 可以破坏封装性。
- 更重要的用途是适合:做Java高级框架,基本上主流框架都会基于反射设计一些通用功能。
注解
1. 注解的概念
1.1 注解
- 用在类上,方法上,成员变量方法,构造器,...上对成分进行编译约束等操作的。
- 注解是JDK1.5的新特性。
- 注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
- 注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。
1.2 注解作用
- 标记。
- 方法重写约束 @Override
- 函数式接口约束。 @FunctionalInterface.
- 现今最牛逼的框架技术多半都是在使用注解和反射。
2. 自定义注解
2.1 自定义注解的格式
[修饰符] @interface 注解名{
// 注解属性
}
2.2 小结
1.注解的定义是@interface
2.注解可以注释类的成分,可以使用多个注解注释同一个成分。
3. 注解的属性
3.1 属性的格式
- 格式1:数据类型 属性名();
- 格式2:数据类型 属性名() default 默认值;
3.2 属性适用的数据类型:
- 八种数据数据类型(int,short,long,double,byte
,char,boolean,float) - String,Class,注解类型。
- 以上类型的数组形式都支持
3.3 小结:
- 注解的属性在使用的时候需要有值!默认值可以不赋值!
3.4 注解的特殊属性名称:value
- value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!!
- 但是如果有多个属性,那么value是不能省略的。
4. 元注解
4.1 简介
- 元注解是sun公司提供的。
- 元注解是用在自定义注解上的注解。
- 元注解是用来注解自定义注解的。
4.2 元注解有两个:
-
@Target:约束自定义注解只能在哪些地方使用,
作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
-
可使用的值定义在ElementType枚举类中,常用值如下
TYPE,类,接口 FIELD, 成员变量 METHOD, 成员方法 PARAMETER, 方法参数 CONSTRUCTOR, 构造方法 LOCAL_VARIABLE, 局部变量
但是默认的注解可以在类,方法,构造器,成员变量,... 使用。
-
@Retention:申明注解的生命周期
- 作用:用来标识注解的生命周期(有效范围)
- 可使用的值定义在RetentionPolicy枚举类中,常用值如下
- SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
- CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
- RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
- 申明注解的作用范围:编译时,运行时。
5. 注解解析
5.1 简介
- 我们会使用注解注释一个类的成分,那么就设计到要解析出这些注解的数据。
- 开发中经常要知道一个类的成分上面到底有哪些注解,注解有哪些属性数据,这都需要进行注解的解析。
5.2 与注解解析相关的接口
Annotation: 注解类型,该类是所有注解的父类。注解都是一个Annotation的对象
-
AnnotatedElement:该接口定义了与注解解析相关的方法
/* 所有的类成分Class, Method , Field , Constructor:都实现了AnnotatedElement接口 他们都拥有解析注解的能力: */ // 根据注解类型获得对应注解对象,会拿父类的注解 T getAnnotation(Class<T> annotationClass); // 获得当前对象上使用的所有注解,返回注解数组 Annotation[] getAnnotations() // 获得当前对象上使用的所有注解,返回注解数组,只包含本类的 Annotation[] getDeclaredAnnotations() // 根据注解类型获得对应注解对象 T getDeclaredAnnotation(Class<T> annotationClass) // 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false boolean isAnnotationPresent(Class<Annotation> annotationClass)
5.3 获取注解数据的原理
- 注解在哪个成分上,我们就先拿哪个成分对象。
- 比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
- 比如注解作用在类上,则要该类的Class对象,,再来拿上面的注解
- 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解
6. 注解模拟Junit框架
定义若干个方法,只要加了MyTest注解,就可以被自动触发执行。
-
分析:
- 定义一个自定义注解MyTest.
- 只能注解方法。
- 定义若干个方法,只要有@MyTest注解的方法就能被触发执行!!没有这个注解的方法不能执行!!
- 定义一个自定义注解MyTest.
小结:
反射+注解+泛型通常是做大型框架的核心技术!!可以做通用框架技术!-
代码实现
动态代理
1. 问题:
- 我们发现我们的业务功能方法,前后的逻辑代码几乎都是一样,只是中间部分不一样
- 如果能够让业务功能只处理自己的核心逻辑,其他的不用写就可以完成,这时候需要用动态代理了!!
2. 核心:
- 做一个代理类,把业务对象的交个代理类,返回被代理对象。
- 以后调用被代理对象的功能,会先触发代理类执行。
- 把业务对象 -> 转成被代理的业务对象
3. 代理类
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- 参数一:给类的加载器,用于加载类。
- 参数二:被代理对象所实现的全部接口,因为被代理的功能都在接口中定义。
- 参数三:代理对象的处理方法:旅行社的功能。