黑马程序员技术交流社区

标题: 【day14】-Junit单元测试、反射与注解 [打印本页]

作者: tianhaolin    时间: 2018-12-2 10:53
标题: 【day14】-Junit单元测试、反射与注解
本帖最后由 tianhaolin 于 2018-12-2 10:55 编辑

第一章、Junit单元测试
1.测试分类
*黑盒测试
*白盒测试
  Junit单元测试就是白盒测试中的一种
2.Junit的使用
1)步骤
    -定义一个测试类(测试用例)
          建议:测试类名 = 被测试的类名+Test 如:CalculatorTest
          包名:xxx.xxx.xx.test
    -定义一个测试方法:可以独立运行
          建议:方法名 = test测试的方法名 如:testAdd()
                返回值 = void
                参数列表 = 空参
    -给方法加一个注解:@Test
           加上这个注解后方法就可以独立运行了
    -导入Junit的依赖环境(点@Test旁边的小灯泡 导入Junit依赖的环境)
2)判定测试
   *红色:失败
   *绿色:成功
   *断言:一般使用断言来判定测试结果
    Assert.assertEquals(expected,result)
    断言输出结果和测试结果相匹配;匹配不成功则测试失败
3)@Before/@After注解
   @Before-修饰的方法在测试方法之前被自动执行,一般用于资源申请
   public void init(){}
   @After-修饰的方法在测试方法之后被自动执行,一般用于资源释放
   public void close(){}

第二章、反射:框架的设计灵魂
1.框架:半成品软件,不能独立运行
       可以在框架的基础上进行软件开发,简化编码
2.反射:将类的各个组成部分封装为其他对象,这就是反射机制
  *Java代码在计算机中的三个阶段
      **Source 源代码阶段:.java/.class文件在硬盘上的阶段
      **Class 类对象阶段: 类加载器将字节码文件加载进内存的阶段(Class类是用来加载所有类的类)
                Class类对象将其他类文件封装成成员变量数组/构造方法数组/成员方法数组.这就是反射机制
      **Runtime阶段:在内存中创建对象的阶段
  *反射的好处
      **可以在程序运行过程中操作这些对象
      **可以解耦,提高程序的可扩展性
3.获取Class对象的三个方式
    *Class.forName("全类名"):将字节码文件加载进内存,返回Class对象(对应Source阶段)
          多用于配置文件,将类名定义在配置文件中,读取文件,加载类
    *类名.class:通过类名的属性.class来获取
          多用于参数的传递
    *对象.getClass():通过对象的方法.getClass()来获取
          多用于对象的获取字节码文件对象的方式
          注意:同一个字节码文件(*.class)在一次程序运行中只会被加载一次,用三种方式获得的Class类对象是同一个
4.Class对象功能
1)暴力反射:忽略权限修饰符的安全检查
    对象(变量/方法/构造).setAccessable(true)
2)获取的功能
  *获取成员变量s
       -Field[] getFields()
          获取所有public修饰的成员变量
       -Field getField(String name)
          获取指定名称的public修饰的成员变量
       -Field[] getDeclaredFields()
          获取所有的成员变量,不考虑修饰符
       -Field getDeclaredField(String name)
          获取指定名称的成员变量
     **Field的方法-在访问私有变量前需要忽略权限修饰符的安全检查
           Object get(Object obj):获取object对象指定成员变量的值
           set(Object obj,Object Value):设置object对象,指定成员变量的value
  *获取构造方法s
    -Constructor<?>[] getConstructors()
    -Constructor<?> getConstructor(类<?>...parameterTypes)
    -Constructor<?>[] getDeclaredConstructors()
    -Constructor<?> getDeclaredConstructor(类<?>...parameterTypes)
        例:
        
[Java] 纯文本查看 复制代码
  
         //1.获取Person的Class对象
         Class personClass = Person.class;
         //2.获取构造器对象
         Constructor constructor = personClass.getConstructor(String.class,int.class);
   *Constructor<?>的方法-用来创建对象:T newInstance(Object...initargets)
           例: Person person = constructor.newInstance("张三",18);
           如果使用空参构造,可以直接使用Class类的静态方法newInstance
           Person person = personClass.newInstance();
  *获取成员方法s
    -Method[] getMethods()
        -Method getMethod(String name,类<?>...parameterTypes)
    -Method[] getDeclaredMethods()
        -Method getgetDeclaredMethod(String name,类<?>...parameterTypes)
        **Method的方法-用来执行方法
          Object invoke(Object obj,Obj...args);
          例:
            
[Java] 纯文本查看 复制代码

//1.获取Person的Class对象
                 Class personClass = Person.class;
//2.获取方法
             Method eat_method = personClass.getMethod("eat", String.class); //3.执行方法
                Person p = new Person();
                eat_method(p,"饭");
  *获取类名称
    -String getName();
3)反射的案例
   *需求:写一个"框架",在不改变框架代码的前提下,可以帮我们去创建任意类的对象,并且执行其中任意方法
   *步骤:
       将需要创建的对象的全类名和需要执行的方法定义在配置文件中
              创建.properties文件,写入配置:
                       className = cn.itcast.domain.Person
               methodName = eat
           在程序中加载读取配置文件
           使用反射技术来加载类文件仅内存
           创建对象
           执行方法
           
   *代码
      
[Java] 纯文本查看 复制代码
public class ReflectTest {
        public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //1.加载文件
        //1.1创建Properties对象
        Properties pro = new Properties();
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取class目录下的配置文件
        //1.2.1.1获取本类的一个类加载器
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        //1.2.1.2使用类加载器去找到pro.properties文件的路径,并转换为流
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        //1.2.2获取文件中的内容
        pro.load(is);
        //2.获取配置文件中定义的数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //3.加载该类进内存
        Class cls = Class.forName(className);
        //4.创建对象
        Object obj = cls.newInstance();
        //5.获取方法对象
        Method method = cls.getMethod(methodName);
        //6.执行方法
        method.invoke(obj);
      }
    }
        
第三章、注解 Annotiation
1.注解的概念
1)注释:说明程序的,是给程序员看的
2)注解:说明程序的,是给解析程序看的
3)注解的定义:
    定义:注解(Annotation),也叫元数据。一种代码级别的说明。
              它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
              它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
    作用分类:
     -编写文档:通过代码里标识的注解生成文档【生成javadoc文档】-也就是API
            按照以下注解代码,使用javadoc可以将注解抽取到doc文档,打开Index.html即为生成的注解文档
             注解编写文档案例:
               
[Java] 纯文本查看 复制代码
       /**
               * 注解 javadoc演示
               * @auther itcat
               * @version 1.0
               * @since 1.5
               */

               public class AnnoDemo01{
               /**
               * 计算两个数的和
               * @param a 整数
               * @param b 整数
               * @return
               */
               public int add(int a, int b) {
                return a + b;
              }
             }


     -代码分析:通过代码里标识的注解对代码进行分析【使用反射】
     -编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】


2.JDK内置注解
1)@Override
    检测被该注解标注的方法是否继承自父类(接口)的
2)@Deprecated(弃用)
    将该注解标注的内容,已过时.
3)@SuppressWarnings
    压制警告:这里的警告不是异常,而是编译文件(IDEA)右侧的黄色横杠显示的警告
        一般写在类上边,@SuppressWarnings("all") 这样这个类的警告都不会显示了

3.注解的格式
1)注解分为两个部分,1是元注解,2是public @interface 注解名称{}
                元注解
                public @interface 注解名称{
                       属性列表
                }
2)注解的本质:注解就是一个接口,该接口默认继承Annotation接口
   public @interface MyAnnotataion  = public interface MyAnnotataion extends java.lang.annotation.Annotation


4.注解的属性:接口中的抽象方法
1)要求
   *属性的返回值数据类型
      -基本数据类型
          -String
          -枚举
          -以上类型的数组
   *定义了属性在使用时,需要给属性赋值
      -如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不进行属性的赋值
          -如果只有一个属性需要赋值,并且属性名叫value,那么使用是可以省略属性名
          -数组赋值时,值使用{}包裹,如果数组里面只有一个值,则大括号可以省略
      注解实例
        定义:
        public @interface MyAnno{
                  int value();
                  String name() default "张三";
                }
                使用:
                @MyAnno(12)          因为只有一个属性需要赋值,而且属性名为value则可以把value省略
                @MyAnno(value = 12)  因为name已经有了default值,所以可以不赋值
                @MyAnno(value = 12,name = "李四")
2)元注解:用于描述注解的注解
    需要掌握的元注解
        *@Target:描述注解能够作用的位置
           **ElementType取值
                -Type:可以作用于类上
                -METHOD:可以作用域方法上
                -FIELD:可以作用域成员变量上
        *@Retention:描述注解能够被保留的阶段(Runtime/Class/Source)
           **RetentionPolicy取值
              -RUNTIME:当前被描述的注解,会保留到class字节码文件中,并被JVM读取到,我们自己定义的注解一般都是这种
              -CLASS
              -SOURCE
        *@Documented:描述注解能否被抽取到api文档中
           类在使用java.doc生成doc的时候(注解要也在该文件夹中),如果注解的元注解有@Documented,则生成的文档中类被该注解注释的地方会标注出来
        *@Inheritred:描述注解是否被子类继承


5.注解的解析(使用)
1)注解解析的过程:
    -获取类的字节码文件对象:类.class
        -获取类的注解对象:  cls.getAnnotation(注解名);
        -获取注解的抽象对象:注解名.method(); //获得了注解的属性值
2)注解的解析案例
   *创建一个新的注解
        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Pro {
            String className();
            String methodName();
        }
   *注解解析
[Java] 纯文本查看 复制代码
    
public class ReflectTest {
        public static void main(String[] args) throws IOException {
        //1获取本类的class对象
        Class cls = ReflectTest.class;
        //2获取注解
        Pro ann = cls.getAnnotation(Pro.class);
        //3.调用注解对象定义的抽象方法,获取属性值
                //其实就是在内存中生成了一个该注解的子类实现对象
        String className = an.className();
                String methodName = an.methodName();
        //4.调用注解的方法
        Method meth = cls.getMethod(methodName);
        meth.invoke(p);
       }
    }



6.注解总结
1)以后大多数时候我们都会使用注解,而不是自己创建注解
2)注解给谁用?
   *编译期
   *解析程序
3)注解不是程序的一部分,而是一个标签








欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2