Java 1.5之前,一般使用命名模式表明有些程序元素需要通过某种工具或者框架进行特殊处理。例如,JUnit测试框架原本要求用户一定要用test作为测试方法名称的开头。
命名模式的缺点:
文字拼写错误导致失败,测试方法没有执行,也没有报错
无法确保它们只用于相应的程序元素上,如希望一个类的所有方法被测试,把类命名为test开头,但JUnit不支持类级的测试,只在test开头的方法中生效
没有提供将参数值与程序元素关联起来的好方法。
注解能解决命名模式存在的问题,下面定义一个注解类型指定简单的测试,它们自动运行,并在抛出异常时失败
(注意,下面的Test注解是自定义的,不是JUnit的实现)
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
@Retention注解有三种
1.RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
2.RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略
3.RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用.
@Target(ElementType.METHOD)表明只有在方法声明中Test注解才是合法的
下面的Sample类使用Test注解,如果拼错Test或者将Test注解应用到除方法外的其他地方,
编译不会通过
public class Sample {
@Test public static void m1() { System.out.println("通过");}
public static void m2() {}
@Test public static void m3() {
throw new RuntimeException("Boom");
}
public static void m4() {}
@Test public void m5() { System.out.println("通过");}
public static void m6() {}
@Test public static void m7() {
throw new RuntimeException("Crash");
}
public static void m8() {}
}
下面是测试运行类:
public class RunTests {
public static void main(String[] args){
//测试的个数
int texts = 0;
//通过的个数
int passed = 0;
try {
Class textClass = Class.forName("com.example.jinruilib.Sample");
for(Method m:textClass.getDeclaredMethods()){
if(m.isAnnotationPresent(Test.class)){
texts++;
try {
m.invoke(null);
passed++;
}catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("测试用例个数"+texts+" 通过个数 "+ passed);
}
}
注解.png
网友评论