Java进阶之单元测试、反射、注解

Junit单元测试

测试分类:
1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
2. 白盒测试:需要写代码的。关注程序具体的执行流程。

测试就是对所完成功能的校验,查看功能是否有缺陷有漏洞。在工作中,每次做完功能后都要进行测试,测试通过才可以结束该功能的编写。测试是开发中很重要的一部分。

测试前提
进行单元测试时,一定先要引入Junit包才可以使用。并且@Test该注解必须在方法名上;

@BeforeClass:针对所有测试,只执行一次,且必须为static void

@Before:初始化方法 (一般用于申请资源,为后续的方法初始化一些环境)

@Test:测试方法,在这里可以测试期望异常和超时时间

@After:释放资源

@AfterClass:针对所有测试,只执行一次,且必须为static void

@Ignore:忽略的测试方法

一个单元测试用例执行顺序为: @BeforeClass –> @Before –> @Test –> @After –> @AfterClass

每一个测试方法的调用顺序为: @Before –> @Test –> @After

public class TestCal {

    @BeforeClass
    public static void init() {
        System.out.println("init...");
    }

    @Before
    public void beforeMethod() {
        System.out.println("beforeMethod...");
    }
    @Test
    public void testCal(){
        Calculator c = new Calculator();
        int result =c.cal(10,10);
        // 这个方法叫断言,既我断言这个代码的执行结果result是1,如果断言
        // 正确则控制台绿色√,否则共色×
        Assert.assertEquals(1,result);
    }
    @After
    public void afterMethod() {
        System.out.println("afterMethod...");
    }

    @AfterClass
    public static void after() {
        System.out.println("after...");
    }
}

输出结果为:

init...
beforeMethod...
afterMethod...
after...

反射

定义:将类的各个组成部分封装为其他对象,这就是反射机制。
好处:

  • 可以在程序运行过程中,操作这些对象。
  • 可以解耦,提高程序的可扩展性。

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射_获取字节码Class对象的三种方式

  1. Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象;

  2. 类名.class:通过类名的属性class获取;

  3. 对象.getClass():getClass()方法在Object类中定义着。
    注意:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

     	1. 获取成员变量们
     		* Field[ ] getFields() :获取所有public修饰的成员变量
     		* Field getField(String name)   获取指定名称的 public修饰的成员变量
    
     		* Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
     		* Field getDeclaredField(String name)  
     	2. 获取构造方法们
     		* Constructor<?>[] getConstructors()  
     		* Constructor<T> getConstructor(类<?>... parameterTypes)  
    
     		* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)  
     		* Constructor<?>[] getDeclaredConstructors()  
     	3. 获取成员方法们:
     		* Method[] getMethods()  
     		* Method getMethod(String name, 类<?>... parameterTypes)  
    
     		* Method[] getDeclaredMethods()  
     		* Method getDeclaredMethod(String name, 类<?>... parameterTypes)  
    
     	4. 获取全类名	
     		* String getName()  
    
public class ReflectDemo {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Class<Person> person=Person.class;//获取一个Person类的class对象
        System.out.println(person);//class java_reflect.Person 
        //首先获取成员变量对象,然后获取内部的每一个变量名
        Field[] fields=person.getDeclaredFields();
        for (Field field : fields) {//使用了declared,表示获取所有的成员变量
            System.out.println(field.getType()+"  "+field.getName());
        }
        /**
         * 这是输出结果
         * class java.lang.String  name
            int  age
            int  score
         */
        System.out.println("=======================");
        //返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。
        //也就是说整个返回的对象包含了该类的指定参数的构造函数对象 
        Constructor<Person> con=person.getConstructor(String.class);
        System.out.println(con.getName()+"构造函数可接受的参数个数:"+con.getParameterCount());
        //输出:java_reflect.Person构造函数可接受的参数个数:1
        System.out.println("=======================");
        //这个是获取的person对象的所有权限等级的方法,但不包括超类的,返回
        //一个方法数组
        Method[] methods=person.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("方法修饰符:"+Modifier.toString(method.getModifiers()));
            System.out.println("方法名:"+method.getName());
            //需要遍历这个参数类型的数组,然后得到每一个参数的类型getType()
            System.out.println("方法参数:"+method.getParameters());
            System.out.println("方法参数个数:"+method.getParameterCount());
            System.out.println("----------------------------");
        }
    }
}

注解

定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

注解就是为了简化开发,避免写过多的代码,不利于程序的扩展以及维护。

JDK中预定义的一些注解

@Override
限定重写父类方法。对于子类中被@Override 修饰的方法,如果存在对应的被重写的父类方法,则正确;如果不存在,则报错。@Override 只能作用于方法,不能作用于其他程序元素。

@Deprecated

用于表示某个程序元素(类、方法等)已过时。如果使用了被@Deprecated修饰的类或方法等,编译器会发出警告。

@SuppressWarnings

抑制编译器警告。指示被@SuppressWarnings修饰的程序元素(以及该程序元素中的所有子元素,例如类以及该类中的方法…)取消显示指定的编译器警告。例如,常见的@SuppressWarnings(value=“unchecked”)

SuppressWarnings注解的常见参数值的简单说明:

  1. deprecation:使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告);
  2. unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告
  3. fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
  4. path:在类路径、源文件路径等中有不存在的路径时的警告;
  5. serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
  6. finally:任何 finally 子句不能正常完成时的警告;
  7. all:关于以上所有情况的警告。

元注解
元注解:用于描述注解的注解

  • @Target:描述注解能够作用的位置
    • ElementType取值(@Target接口的方法,但更像是一种属性写法):
      • TYPE:可以作用于类上
      • METHOD:可以作用于方法上
      • FIELD:可以作用于成员变量上
  • @Retention:描述注解被保留的阶段
  • @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
  • @Documented:描述注解是否被抽取到api文档中
  • @Inherited:描述注解是否被子类继承

1.@Retention: 定义注解的保留策略

  • @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
  • @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
  • @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
    首 先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。

接下来写个小demo,首先自定义一个注解@Check,然后写一个类,类中定义了很多方法,如果方法上带有@Check这个注解,我们就执行他,如果错误就生成日志信息。

// 自定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {

}
// 写一个类,类中有一些方法,并带有@Check注解
public class Calculator {
    @Check
    public void add() {
        System.out.println("1+0="+(1+0));
    }
    @Check
    public void div() {
        System.out.println("1/0="+(1/0));
    }
}
public class Demo {
    public static void main(String[] args) throws IOException {
        Calculator c=new Calculator();// 获取相应的实体类,也可以用Class.forName(“全限定类名”)的方式来生成实例对象
        Class<?> claClass=c.getClass();
        Method[] methods=claClass.getMethods();// 反射出其中的方法们
        int count=0;
        // 运用IO流
        BufferedWriter bw=new BufferedWriter(new FileWriter("D:/file/d.txt"));
        for (Method method : methods) {
        // 遍历方法们,如果该方法带有相应注解,则
            if (method.isAnnotationPresent(Check.class)) {
                try {
                // 调用该方法
                    method.invoke(c);
                } catch (Exception e) {
                    count++;
                    // 错误就打印日志信息
                    bw.write("方法名称"+method.getName());
                    bw.newLine();
                    bw.write("异常名称"+e.getCause().getClass().getName());
                    bw.newLine();
                    bw.write("异常内容"+e.getCause().getMessage());
                    bw.newLine();
                    bw.write("这是第"+count+"条异常");
                    bw.write("--------------------------------");
                    bw.newLine();
                }
            }
        }
        // 释放资源
        bw.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值