怎样用Java的注解(Annotation)实现一个简单的测试框架

wen java案例 49

本文目录导读:

怎样用Java的注解(Annotation)实现一个简单的测试框架

  1. 自定义注解定义
  2. 测试执行器
  3. 断言工具类
  4. 使用示例
  5. 运行测试
  6. 运行结果
  7. 扩展功能

我来教你用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注解的核心用法:

  1. 定义注解:使用@interface和元注解
  2. 解析注解:通过反射获取注解信息
  3. 处理注解:根据注解执行相应逻辑

你可以基于这个框架扩展到更复杂的功能,比如支持参数化测试、测试套件、报告生成等。

抱歉,评论功能暂时关闭!