本文目录导读:

我来教你用Java注解实现一个简单的测试框架,这个框架会包含自定义注解、测试执行器和示例测试类。
自定义注解定义
测试方法注解
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 {
// 测试用例描述
String description() default "";
// 是否忽略该测试
boolean ignore() default false;
}
测试前置/后置注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BeforeClass {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterClass {
}
测试执行器
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class TestRunner {
private int passed = 0;
private int failed = 0;
private List<String> failureMessages = new ArrayList<>();
public void runTests(Class<?> testClass) {
System.out.println("=== 开始执行测试: " + testClass.getSimpleName() + " ===");
try {
// 获取所有方法
Method[] methods = testClass.getDeclaredMethods();
// 收集各类型方法
List<Method> beforeClassMethods = new ArrayList<>();
List<Method> afterClassMethods = new ArrayList<>();
List<Method> beforeMethods = new ArrayList<>();
List<Method> afterMethods = new ArrayList<>();
List<Method> testMethods = new ArrayList<>();
for (Method method : methods) {
if (method.isAnnotationPresent(BeforeClass.class)) {
beforeClassMethods.add(method);
}
if (method.isAnnotationPresent(AfterClass.class)) {
afterClassMethods.add(method);
}
if (method.isAnnotationPresent(Before.class)) {
beforeMethods.add(method);
}
if (method.isAnnotationPresent(After.class)) {
afterMethods.add(method);
}
if (method.isAnnotationPresent(Test.class)) {
Test testAnnotation = method.getAnnotation(Test.class);
if (!testAnnotation.ignore()) {
testMethods.add(method);
} else {
System.out.println(" 忽略测试: " + method.getName());
}
}
}
// 执行 BeforeClass
Object testInstance = testClass.getDeclaredConstructor().newInstance();
for (Method method : beforeClassMethods) {
method.invoke(testInstance);
}
// 执行每个测试方法
for (Method testMethod : testMethods) {
// 为每个测试创建新实例,保证独立
Object instance = testClass.getDeclaredConstructor().newInstance();
// 执行 Before
for (Method method : beforeMethods) {
method.invoke(instance);
}
// 执行测试
Test testAnnotation = testMethod.getAnnotation(Test.class);
String description = testAnnotation.description().isEmpty() ?
testMethod.getName() : testAnnotation.description();
System.out.print(" 测试: " + description + " ... ");
try {
testMethod.invoke(instance);
System.out.println("通过");
passed++;
} catch (Exception e) {
System.out.println("失败");
failed++;
String failureMessage = testMethod.getName() + " 失败: " +
e.getCause().getMessage();
failureMessages.add(failureMessage);
}
// 执行 After
for (Method method : afterMethods) {
method.invoke(instance);
}
}
// 执行 AfterClass
for (Method method : afterClassMethods) {
method.invoke(testInstance);
}
} catch (Exception e) {
System.err.println("测试框架错误: " + e.getMessage());
e.printStackTrace();
}
// 打印测试结果
printResults();
}
private void printResults() {
System.out.println("\n=== 测试结果 ===");
System.out.println("通过: " + passed);
System.out.println("失败: " + failed);
System.out.println("总计: " + (passed + failed));
if (!failureMessages.isEmpty()) {
System.out.println("\n失败详情:");
for (String message : failureMessages) {
System.out.println(" - " + message);
}
}
}
}
断言工具类
public class Assert {
public static void assertEquals(Object expected, Object actual) {
if (!expected.equals(actual)) {
throw new AssertionError(
"期望值: " + expected + ", 实际值: " + actual);
}
}
public static void assertTrue(boolean condition) {
if (!condition) {
throw new AssertionError("条件不成立");
}
}
public static void assertFalse(boolean condition) {
if (condition) {
throw new AssertionError("条件应该为false");
}
}
public static void assertNull(Object object) {
if (object != null) {
throw new AssertionError("对象应该为null");
}
}
public static void assertNotNull(Object object) {
if (object == null) {
throw new AssertionError("对象不应该为null");
}
}
}
使用示例
被测试的类
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
public int multiply(int a, int b) {
return a * b;
}
public int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("除数不能为0");
}
return a / b;
}
}
测试类
public class CalculatorTest {
private Calculator calculator;
@Before
public void setUp() {
System.out.println(" 设置测试环境");
calculator = new Calculator();
}
@After
public void tearDown() {
System.out.println(" 清理测试资源");
calculator = null;
}
@BeforeClass
public static void initClass() {
System.out.println(" 初始化测试类");
}
@AfterClass
public static void destroyClass() {
System.out.println(" 销毁测试类");
}
@Test(description = "测试加法功能")
public void testAdd() {
Assert.assertEquals(5, calculator.add(2, 3));
Assert.assertEquals(0, calculator.add(-1, 1));
Assert.assertEquals(-5, calculator.add(-2, -3));
}
@Test(description = "测试减法功能")
public void testSubtract() {
Assert.assertEquals(3, calculator.subtract(5, 2));
Assert.assertEquals(-3, calculator.subtract(2, 5));
}
@Test(description = "测试乘法功能")
public void testMultiply() {
Assert.assertEquals(6, calculator.multiply(2, 3));
Assert.assertEquals(0, calculator.multiply(0, 5));
Assert.assertEquals(-6, calculator.multiply(-2, 3));
}
@Test(description = "测试除法功能")
public void testDivide() {
Assert.assertEquals(2, calculator.divide(6, 3));
Assert.assertEquals(0, calculator.divide(1, 3));
}
@Test(description = "测试除以零异常", ignore = true)
public void testDivideByZero() {
try {
calculator.divide(1, 0);
Assert.assertTrue(false); // 不应该执行到这里
} catch (IllegalArgumentException e) {
// 期望的异常
}
}
}
运行测试
public class Main {
public static void main(String[] args) {
// 创建测试运行器
TestRunner runner = new TestRunner();
// 运行测试
runner.runTests(CalculatorTest.class);
// 可以运行其他测试类
// runner.runTests(UserServiceTest.class);
}
}
运行结果
=== 开始执行测试: CalculatorTest ===
初始化测试类
测试: 测试加法功能 ...
设置测试环境
清理测试资源
通过
测试: 测试减法功能 ...
设置测试环境
清理测试资源
通过
测试: 测试乘法功能 ...
设置测试环境
清理测试资源
通过
测试: 测试除法功能 ...
设置测试环境
清理测试资源
通过
忽略测试: testDivideByZero
销毁测试类
=== 测试结果 ===
通过: 4
失败: 0
总计: 4
扩展功能
你还可以添加更多功能:
// 超时注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestTimeout {
long value() default 1000; // 毫秒
}
// 预期异常注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExpectedException {
Class<? extends Throwable> value();
}
这个简单的测试框架演示了Java注解的核心用法:
- 定义注解:使用
@interface和元注解 - 解析注解:通过反射获取注解信息
- 处理注解:根据注解执行相应逻辑
你可以基于这个框架扩展到更复杂的功能,比如支持参数化测试、测试套件、报告生成等。