Effecitve Java 注解优先于命名模式

Java 1.5之前,一般使用命名模式表明有些程序元素需要通过某种工具或者框架进行特殊处理。例如,JUnit测试框架原本要求用户一定要用test作为测试方法名称的开头。

命名模式的缺点:1.文字拼写错误导致失败,测试方法没有执行,也没有报错  2.无法确保它们只用于相应的程序元素上,如希望一个类的所有方法被测试,把类命名为test开头,但JUnit不支持类级的测试,只在test开头的方法中生效 3.没有提供将参数值与程序元素关联起来的好方法。

 

注解能解决命名模式存在的问题,下面定义一个注解类型指定简单的测试,它们自动运行,并在抛出异常时失败(注意,下面的Test注解是自定义的,不是JUnit的实现)

复制代码

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}

复制代码

@Retention(RetentionPolicy.RUNTIME)表明Test注解在运行时保留
@Target(ElementType.METHOD)表明只有在方法声明中Test注解才是合法的

下面的Sample类使用Test注解,如果拼错Test或者将Test注解应用到除方法外的其他地方,
编译不会通过

复制代码

public class Sample {
    @Test public static void m1() {

    }
    public static void m2() {
        
    }
    @Test public static void m3() {
        throw new RuntimeException("Boom");
    }
    public static void m4() {
        
    }
    @Test public void m5() {
        
    }
    public static void m6() {
        
    }
    @Test public static void m7() {
        throw new RuntimeException("Crash");
    }
    public static void m8() {
        
    }
    
}

复制代码

测试Sample的测试运行类:

复制代码

public class RunTests {

    public static void main(String[] args) throws ClassNotFoundException {
        int tests = 0;
        int passed = 0;
        Class testClass = Class.forName("ex_35.Sample");
        for(Method m : testClass.getDeclaredMethods()) {
            if(m.isAnnotationPresent(Test.class)) {
                tests++;
                try {
                    m.invoke(null);
                    passed++;
                } catch(InvocationTargetException wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    System.out.println(m + " failed: " + exc);
                } catch(Exception e) {
                    System.out.println("INVALID @Test: " + m);
                }
                
            }
        }
        System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);
    }

}

复制代码

 
运行结果:
public static void ex_35.Sample.m3() failed: java.lang.RuntimeException: Boom
INVALID @Test: public void ex_35.Sample.m5()
public static void ex_35.Sample.m7() failed: java.lang.RuntimeException: Crash
Passed: 1, Failed: 3
针对只有在抛出特殊异常才成功的注解:

复制代码

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 ExceptionTest {
    Class<? extends Exception> value();
}

复制代码

 

JUnit提供一个完整的测试框架(下面例子基于Junit4)

需要被测试的类:

复制代码

public class Calculator {
    private static int result; // 静态变量,用于存储运行结果  
    public void add(int n) {  
        result = result + n;  
    }  
    public void substract(int n) {  
        result = result - 1;  //Bug: 正确的应该是 result =result-n  
    }  
    public void multiply(int n) {  
    }         // 此方法尚未写好  
    public void divide(int n) {  
        result = result / n;  
    }  
    public void square(int n) {  
        result = n * n;  
    }  
    public void squareRoot(int n) {  
        for (; ;) ;            //Bug : 死循环  
    }  
    public void clear() {     // 将结果清零  
        result = 0;  
    }  
    public int getResult() {  
        return result;  
    } 
}

复制代码

 

用于测试Calculator类的测试类:

复制代码

public class CalculatorTest {
    
    private static Calculator calculator = new Calculator();
    
    @Before
    public void setUp() throws Exception {
        calculator.clear();
    }

    @Test
    public void testAdd() {
        calculator.add(2);
        calculator.add(3);
        assertEquals(5, calculator.getResult());
    }

    @Test
    public void testSubstract() {
        calculator.add(10);  
        calculator.substract(2);  
        assertEquals(8, calculator.getResult());  
    }

    @Ignore("Multiply() Not yet implemented")  
    @Test
    public void testMultiply() {
        //fail("Not yet implemented");
    }

    @Test
    public void testDivide() {
        calculator.add(8);  
        calculator.divide(2);  
        assertEquals(4, calculator.getResult());  
    }
    
    @Test(timeout = 1000)
    public void squareRoot() {
        calculator.squareRoot(4);
        assertEquals( 2 , calculator.getResult()); 
    }
    
    @Test(expected = ArithmeticException.class)
    public void divideByZero() {
        calculator.divide(0);
    }

}

复制代码

通过Junit Test来运行CalculatorTest,结果:

明确告诉我们哪些测试出错。

 

除了编写测试框架的程序员外,我们不需要定义注解类型。鼓励使用Java平台提供的预定义注解类型,保证跨平台性,考虑使用IDE或者静态分析工具,如Junit的图形界面,方便在测试出错修改。

已标记关键词 清除标记
相关推荐
<p> <b><span style="background-color:#FFE500;">【超实用课程内容】</span></b> </p> <p> <br /> </p> <p> <br /> </p> <p> 本课程内容包含讲解<span>解读Nginx的基础知识,</span><span>解读Nginx的核心知识、带领学员进行</span>高并发环境下的Nginx性能优化实战,让学生能够快速将所学融合到企业应用中。 </p> <p> <br /> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><br /> </b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b><span style="background-color:#FFE500;">【课程如何观看?】</span></b> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> PC端:<a href="https://edu.csdn.net/course/detail/26277"><span id="__kindeditor_bookmark_start_21__"></span></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a> </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 移动端:CSDN 学院APP(注意不是CSDN APP哦) </p> <p style="font-family:Helvetica;color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 本课程为录播课,课程永久有效观看时长,大家可以抓紧时间学习后一起讨论哦~ </p> <p style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <br /> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <strong><span style="background-color:#FFE500;">【学员专享增值服务】</span></strong> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> <b>源码开放</b> </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化 </p> <p class="ql-long-24357476" style="font-family:"color:#3A4151;font-size:14px;background-color:#FFFFFF;"> 下载方式:电脑登录<a href="https://edu.csdn.net/course/detail/26277"></a><a href="https://edu.csdn.net/course/detail/27216">https://edu.csdn.net/course/detail/27216</a>,播放页面右侧点击课件进行资料打包下载 </p> <p> <br /> </p> <p> <br /> </p> <p> <br /> </p>
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页