今日内容
1. Junit单元测试
2. 反射
3. 注解
Junit 单元测试
* 测试分类
1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出所需的值
2. 白盒测试:需要写代码,需要关注代码的执行流程
* Junit使用:白盒测试
* 步骤:
1. 定义一个测试类(测试用例)
* 建议:
* 测试类名:被测试的类名Test Calculator
* 包名:xxx.xxx.xx.test cn.itcast.test
2. 定义测试方法:可以独立运行
* 建议:
* 方法名:test测试的方法名 testAdd()
* 返回值:void
* 参数列表:空参
3. 给方法加 @Test
4. 看是不是红色:通过断言来处理结果
* 红色:不成功
* 绿色:成功
5. 导入junit依赖环境
* 补充:
* @Before:
* 修饰的方法会在测试方法之前自动执行
* @After:
* 修饰的方法会在测试方法之后执行
反射:框架设计的灵魂
* 框架:半成品的软件。可以在框架的基础上进行开发,简化代码
* 反射:将类的各个组成部分封装为其他对象,这就是反射机制
* 获得class对象的方式:
1. class.forName("全类名"):将字节码文件加载到内存,返回
* 多用于配置文件,将类名定义在配置文件里。读取文件,加载类
2. 类名.class: 通过类名的属性class获取
* 多用于参数的传递
3. 对象.getcalss(): getClass()方法在Object类中定义
* 多用于对象的获取字节码的方式
* 结论:
同一个字节码文件(*.class)在一次程序运行的过程中,只会加载一次,不论通过那种方式获取的class对象都是相同的
* class对象的功能:
* 获取功能:
1. 获取成员变量:
* Field[] getFields() :获取所有public修饰的成员变量
* Field getField(String name):获取指定名称的public的成员变量
* Field[] getDeclaredFields():获取所有成员变量,不考虑修饰符
* Field getDeclaredField(String name)
2. 获取构造方法:
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructors(类<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()
* Constructor<T> getDeclaredConstructors(类<?>... parameterTypes)
3. 获取成员方法
* Method[] getMethods()
* Method getMethod(String name,类<?>... parameterTypes)
* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name,类<?>... parameterTypes)
4. 获取类名
* String getName()
* Field:成员变量:
* 操作:
1. 设置值
* void set(Object obj, Object value)
2. 获取值
* get(Object obj)
3. 忽略访问修饰符,暴力反射
* setAccessible(true)
* Constructor:构造方法
* 创建对象:
* T newInstance(Object... initargs)
* 如果使用空参数构造方法创建对象,操作简化为:Class对象的newInstance
* Method:方法对象:
* 执行方法:
* Object invoke(Object obj,Object... args)
* 获取方法名:
* String getName: 获取方法名
* 案例:
* 需求:写一个“框架”,不能改变该类的代码,可以帮助我们创建任意对象,并且执行任意方法
* 步骤:
1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
2. 在程序中加载读取配置文件
3. 使用反射技术来价值类文件的内容
4. 创建对象
5. 执行方法
注解
* 概念:说明程序,给计算机看的
* 注释:用文字描述程序的,给程序员看的
* 定义: 注解,可以看作是对 一个 类/方法 的一个扩展的模版,每个 类/方法 按照注解类中的规则,来为 类/方法 注解不同的参数,在用到的地方可以得到不同的 类/方法 中注解的各种参数与值
* 概念的描述:
* JDK1.5后的新特性
* 说明程序
* 使用注解名称:@注解名称
* 作用与分类:
1. 编写文档:通过代码里标记的元素据生产文档[生产doc文档]
2. 代码分析:通过代码里标记的元素据对代码进行分析[使用反射]
3. 编写文档:通过代码里标记的元素据让编译器能够实现基本的编译检查[Override]
* JDK中预定的一些注解
* @Override:限定父类重写方法,这可以确保子类确实重写了父类的方法,避免出现低级错误
* @Deprecated:标示已过时,注解用于表示某个程序元素类,方法等已过时,
* @SuppressWarnings :抑制编译器警告,被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告
* 一般传递all @SupperessWarnings("all")
* 自定义的注解
* 格式:
元注解
public @interface 注解名称{
属性列表;
}
* 注解的本质:就是一个接口,默认继承于Annotation接口
* public interface MyAnno extends java.lang.annotation.Annotation {}
* 属性:接口中的抽象方法
* 要求:
1. 属性的返回值类型
* 基本数据类型
* String
* 枚举
* 注解
* 以上类型的数组
2. 定义了属性,在使用时需要给属性赋值
1. 如果定义属性时,使用default关键字给属性默认初始值,则使用注解时可以不进行属性的赋值
2. 如果只有一个属性需要赋值,且名称是value,则value可以省略,直接定义值
3. 数组赋值时,值需要用{}包裹。如果数组中只有一个值,则{}可以省略
* 元注解:描述注解的注解
* @Target:描述注解能作用的位置
* ElementType取值:
* TPYE:可以作用于类上
* METHOD:作用于方法上
* FIELD:作用于成员变量上
* @Retention:描述注解被保留的位置
* @Retention(RetentionPolicy.RUNTIME):当前被描述的注释,会保留到class字节码文件中,并被JVM读取
* @Documented:描述注解是否被抽象到api文档中
* @Inherited:描述注解是否被子类继承
* 在程序中使用(解析)注解:获取注解中定义的属性值
1. 获取注解定义的位置的对象 Class,Method,Field
2. 或取指定的注解
* getAnnotation(Class):在内存中生产了一个注解接口的子类实现对象
public class ProImpl implements Pro{
public String className(){
return "cn.itcase.annotation.Demo1";
}
public String methodName(){
return "show";
}
* 小结:
1. 以后大多数时间,我们会使用注解,而不是自定义注解
2. 注解给谁用?
* 给编译器
* 给解析程序用
3. 注解不是程序的一部分,可以理解为一个标签
public static void main(String[] args) throws IOException {
Calculator c = new Calculator();
Class<? extends Calculator> cls = c.getClass();
Method[] methods = cls.getMethods();
int number = 0;
File file;
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("-------------");
bw.newLine();
}
}
}
bw.write("本次测试一共出现"+number+"次异常");
bw.flush();
bw.close();
}