zoukankan      html  css  js  c++  java
  • Java反射reflection与注解annotation的应用(自动测试机)

    一.关于自动测试机

    1.什么是自动测试机?

    对类中的指定方法进行批量测试的工具

    2.自动测试机有什么用?

    a.避免了冗长的测试代码

    当类中的成员方法很多时,对应的测试代码可能会很长,使用测试能够让测试代码非常简洁

    b.降低了类与测试代码之间的耦合性

    以防万一,测试时应该对类中所有方法进行测试。当我们对类中的一个方法做改动时,很可能我们的测试代码也要做相应改动(如改变了方法名,返回值类型等等),使用测试机能降低类与测试代码之间的耦合性,大大降低不必要的工作量。

    c.增加了测试的灵活性

    测试类与待测试类往往是分开的,设置测试参数时可能往往需要查看具体的方法体(寻找边界参数),这样很不方便。使用测试机的话,测试参数就在对应方法声明的位置(给方法添加相应注解),易于灵活修改参数。

    3.测试机的原理

    利用注解与反射就可以实现测试机了,原理非常简单,之前以为注解就是一种类型,没想过往这方面来应用...具体原理是:

    根据待测试方法参数类型声明自定义注解 --> 为方法添加相应的注解 --> 利用反射机制编写测试机代码

    二.参考资料

    这么犀利的东西当然不是由我提出的,前辈在很久之前就提出了,链接:http://blog.csdn.net/rj042/article/details/6399965

    P.S.建议把链接博文与本文一起看,原文介绍了很多相关的基础知识,本文是在其基础上展开的实践

    三.实践

    1.原文提出了自动测试机的问题:

    -------

    要求:
    (1)定义一个单值注解TestCase,使其可以注解方法,并且可以被保留到程序运行时
    注解的属性类型为String,要求可以使用简写方式为属性赋值
    (2)定义一个类MyClass,要求有三个方法Method1、2、3
    方法的参数、返回值类型均为String类型,返回值为传入的参数
    使用(1)中的注解来注释Method1、3,并对属性参数赋值
    (3)定义一个测试类TestMyClass,要求使用反射来测试MyClass中所有的被TestCase注解的方法
    并将注解的属性值作为参数,调用相应方法来返回测试结果
    -------以上内容摘自原文(直接把题目要求粘过来了...)
    2.原文给出的代码几乎没有注释,而且拿来跑完了也不知道程序到底干了什么,可能前辈只是想演示一下过程吧
    小菜鸟表示没有看懂,就对其源码进行了详细的注释,以求彻底弄明白其原理
    3.上代码(注释已经非常详细了)
    [待测试类 Methods.java]
    //定义一个类Methods,要求有三个方法Method1、2、3
    //方法的参数、返回值类型均为String类型,返回值为传入的参数
    //使用自定义的注解来注释Method1、3,并对属性参数赋值
    
    public class Methods {
    
    	/**
    	 * @param args
    	 */
    	@Annotation("Param_1")//对Method1进行注解,表示自动测试机会对Method1感兴趣
    	public String Method1 (String s) {
    		//do something...like
    		s += "_X";
    		
    		return s;
    	}
    
    	//不对Method2进行注解,自动测试机将滤去Method2
    	public String Method2 (String s) {
    		//do something...like
    		s += "_XX";
    		
    		return s;
    	}
    
    	@Annotation("Param3")//同Method1
    	public String Method3 (String s) {
    		//do something...like
    		s += "_XXX";
    
    		return s;
    	}
    
    }
    

    [自定义注解类 Annotation.java]

    import java.lang.annotation.*;
    
    //定义一个单值注解Annotation,使其可以注解方法,并且可以被保留到程序运行时
    //注解的属性类型为String,要求可以使用简写方式为属性赋值
    
    @Target ({ElementType.METHOD})//声明该注解的作用对象,可以是多个Type值
    @Retention (RetentionPolicy.RUNTIME)//声明该注解可以被保留到程序运行时
    public @interface Annotation {
    	//此处定义的value既是属性也是方法,相当于"value", value这样的键值对
    	String value();
    	//没有成员的注解叫标记注解
    	//只有一个成员的注解叫单值注解
    	//有多个成员的注解叫多值注解
    }
    

    [测试类(自动测试机) TestAnnotation.java]

    import java.lang.reflect.*;
    
    //定义一个测试类TestAnnotation,要求使用反射来测试Methods中所有的被Annotation注解的方法
    //并将注解的属性值作为参数,调用相应方法来返回测试结果
    
    public class TestAnnotation {
    	/*
    	 * 这就是所谓的自动测试机
    	 * 即用注解给定的值作为待测试方法的参数,对指定类中的所有方法进行批量测试
    	 * 避免了冗长的测试代码
    	 * 
    	 * */
    	
    	@SuppressWarnings("rawtypes")
    	public static void main(String [] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException {
    		//利用反射机制根据类名获取类的实例,不同于一般的引用
    		//Class类的对象(实例、引用...)是普通对象的工厂
    		//也就是说对一个类A而言,A的class对象只有唯一的一个,而A的普通对象a1, a2, a3...可以有很多个
    		//new A() --> 判断是否存在A的Class对象,不存在则创建之,存在则继续 --> 根据Class对象创建普通对象
    		Class c = Class.forName("Methods");
    		
    		//利用反射获取类中声明的所有方法
    		Method [] ms = c.getDeclaredMethods();
    		System.out.println("<自动测试机已启动...>
    ");
    		for (Method m : ms) {
    			System.out.println("start{");
    			
    			String name = m.getName();
    			//判断方法是否被注解了指定注解
    			if(m.isAnnotationPresent(Annotation.class)) {
    				System.out.println("正在测试 " + name + " 方法");
    				//获取注解对象
    				Annotation anno = m.getAnnotation(Annotation.class);
    				//获取注解的值,因为Annotation是单值注解,直接取值
    				String s = anno.value();
    				//获取类的实例
    				Object obj = c.newInstance();
    				System.out.println("传入参数为 " + s);
    				//调用m方法
    				Object returnObj = m.invoke(obj, s);
    				System.out.println("返回值为 " + returnObj);
    				System.out.println(name + " 方法测试完毕");
    			}
    			else
    				System.out.println(m.getName() + " 方法没有被注解,测试机跳过该方法");
    			
    			System.out.println("}end
    ");
    		}
    		
    		System.out.println("<...自动测试机已关闭>");
    	}
    }
    

    4.运行结果

    <自动测试机已启动...>
    
    start{
    正在测试 Method1 方法
    传入参数为 Param_1
    返回值为 Param_1_X
    Method1 方法测试完毕
    }end
    
    start{
    Method2 方法没有被注解,测试机跳过该方法
    }end
    
    start{
    正在测试 Method3 方法
    传入参数为 Param3
    返回值为 Param3_XXX
    Method3 方法测试完毕
    }end
    
    <...自动测试机已关闭>
    

    四.总结

    例程序中只是为了说明测试机的原理,只能对特定类的特定方法进行测试,不过不用担心。

    反射机制被誉为Java最让人兴奋的东西之一,绝对不是吹的。

    反射机制允许通过子类来获取父类,并以此展开,最终可以得到清晰的类层次结构。

    对多个类进行测试也很简单,我们只需要创建一个类名数组即可,循环什么的,计算机最喜欢做了。

    当然,利用[反射 + 注解]来进行自动测试还有一个优点就是可以测试一个类的家族成员,父亲,爷爷...这一点是单纯的测试代码所无法想象的。

  • 相关阅读:
    IE无法引入css文件
    各个浏览器的兼容性及解决方法小结
    position的用法小结
    vertical-align的理解
    月薪5K和月薪10K,是能力问题还是公司问题?
    程序员如何在QQ群、微信群里装逼?
    一个计算机专业毕业生工作 5 年后的困惑
    CTO 比普通程序员强在哪?
    干程序员辣么久,你为什么还没有年薪60万?
    做一个App究竟要花多少钱?
  • 原文地址:https://www.cnblogs.com/ayqy/p/3751113.html
Copyright © 2011-2022 走看看