分享如何创建自定义的注解 @Test 和 @TestInfo 去模拟一个简单的单元测试框架。
1. @Test Annotation
package com.testunit.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
// 是否忽略这个测试例子
public boolean enable() default true;
}
2. @TestInfo Annotation
@TestInfo放在class上,存储测试的信息。这里演示返回不同的类型 - enum, array, string
package com.testunit.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TestInfo {
public enum Priority{
LOW, MEDIUM,HIGH
}
public Priority priority() default Priority.MEDIUM;
public String[] tags() default "";
public String createBy() default "Matt-jarvi";
public String lastModified() default "2016-2-24";
}
3. 单元测试例子
创建一个简单的测试用例,并且用新的自定义注解
package com.testunit.demo;
import com.testunit.demo.TestInfo.Priority;
@TestInfo(priority=Priority.LOW,
tags = {"testExample","test"},
createBy = "jarvi-matt",
lastModified = "02/24/2016"
)
public class TestExample {
@Test
public void testA(){
throw new RuntimeException("这个例子总是失败!");
}
@Test(enable = false)
public void testB(){
//System.out.println("测试enable = false的情况");
}
@Test(enable = true)
public void testC(){
//System.out.println("测试enable = true的情况");
}
}
4. Java 反射 - 处理注解
下面的例子演示如何用Java的反射APIs 去处理自定义的注解
package com.testunit.demo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class RunTest {
public static void main(String[] args) {
System.out.println("Testing...");
int passed = 0;
int failed = 0;
int count = 0;
int ignore = 0;
Class<TestExample> clazz = TestExample.class;
//解析@TesterInfo
//如果存在,得到@TesterInfo的信息并打印
if(clazz.isAnnotationPresent(TestInfo.class)){
TestInfo testInfo = clazz.getAnnotation(TestInfo.class);
System.out.println("测试信息如下:");
System.out.printf("%nTestClass :%s",clazz.getSimpleName());
System.out.printf("%nPriority :%s",testInfo.priority());
System.out.printf("%nCreateBy :%s",testInfo.createBy());
System.out.printf("%nLastModified :%s",testInfo.lastModified());
System.out.printf("%nTags :%s%n%n",Arrays.asList(testInfo.tags()));
}
//解析@Test
for(Method method : clazz.getDeclaredMethods()){
if(method.isAnnotationPresent(Test.class)){
Test test = method.getAnnotation(Test.class);
//test为true 执行该方法,否则不执行
if(test.enable() == true){
try {
method.invoke(clazz.newInstance());
System.out.printf("%n%s - 测试'%s'执行完成 - 通过",++count,method.getName());
passed++;
} catch (Exception e) {
failed++;
System.out.printf("%n%s - 测试'%s'执行完成 - 失败: %s ",++count,method.getName(),e.getCause());
}
}else{
System.out.printf("%n%s - 测试'%s'不执行 - 忽略",++count,method.getName());
ignore++;
}
}
}
System.out.printf("%n%nResult >> Total : %s, Passed: %s, Failed: %s, Ignore: %s",count,passed,failed,ignore);
}
}
运行结果:
Testing...
测试信息如下:
TestClass :TestExample
Priority :LOW
CreateBy :jarvi-matt
LastModified :02/24/2016
Tags :[testExample, test]
1 - 测试'testB'不执行 - 忽略
2 - 测试'testA'执行完成 - 失败: java.lang.RuntimeException: 这个例子总是失败!
3 - 测试'testC'执行完成 - 通过
Result >> Total : 3, Passed: 1, Failed: 1, Ignore: 1
References