Junit單元測(cè)試,反射,注解

一,Junit單元測(cè)試

測(cè)試分類:
黑盒測(cè)試(不需要寫代碼,給輸入值,看程序是否能夠輸出期望的值)和白盒測(cè)試(需要寫代碼,關(guān)注程序具體的執(zhí)行流程)。
Junit使用步驟:
(1)定義一個(gè)測(cè)試類(測(cè)試用例)
建議:測(cè)試類名:被測(cè)試的類名Test;包名:xxx.xxx.xx.test
(2)定義測(cè)試方法:可以獨(dú)立運(yùn)行
建議:方法名:test測(cè)試的方法名;返回值:void;參數(shù)列表:空參。
(3)給方法加注解@Test
(4)導(dǎo)入Junit依賴
判定結(jié)果:
紅色:失??;綠色:成功。
一般會(huì)使用斷言操作來處理結(jié)果

Assert.assertEquals(3,result);//期望結(jié)果,斷言結(jié)果
 /**
     * 初始化方法:
     * 用于資源申請(qǐng),所有測(cè)試方法在執(zhí)行之前都會(huì)先執(zhí)行該方法
     */
    @Before
    public void init(){
        System.out.println("init...");
    }

    /**
     * 釋放資源方法:
     * 用于在所有測(cè)試方法執(zhí)行完后,都會(huì)自動(dòng)執(zhí)行該方法
     */
    @After
    public void close(){
        System.out.println("close...");
    }

二,反射

是框架設(shè)計(jì)的靈魂。
定義:將類的各個(gè)組成部分封裝為其他對(duì)象,這就是反射機(jī)制。
好處:
(1)可以在程序運(yùn)行過程中,操作這些對(duì)象。
(2)可以解耦,提高程序的可擴(kuò)展性。
獲取class對(duì)象的方式:
(1)Class.forName("全類名"):將字節(jié)碼文件加載進(jìn)內(nèi)存,返回Class對(duì)象。
多用于配置文件,將類名定義在配置文件中。讀取文件,加載類。
(2)類名.class:通過類名的屬性class獲取。
多用于參數(shù)的傳遞
(3)對(duì)象.getClass():getClass()方法在Object類中定義著。
多用于對(duì)象的獲取字節(jié)碼的方式

Class cls1 = Class.forName("cn.itcast.day12.demo01.test.Person");
        System.out.println(cls1);
        //(2)
        Class cls2 = Person.class;
        System.out.println(cls2);
        //(3)
        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

結(jié)論:同一個(gè)字節(jié)碼文件(*.class)在一次程序運(yùn)行過程中,只會(huì)被加載一次,不論通過哪一種方式獲取的Class對(duì)象都是同一個(gè)。
Class對(duì)象功能:
獲取功能:獲取成員變量們,獲取構(gòu)造方法們,獲取成員方法們,獲取類名。
Field[] getFields()獲取所有public修飾的成員變量;
Field getField(String name)獲取指定名稱的public修飾的成員變量;

public static void main(String[] args) throws Exception {
        //0,獲取Person的Class對(duì)象
        Class personClass = Person.class;
        //1,獲取成員變量getFields(),getField(),getDeclaredFields(),getDeclaredField()
        Field[] fields = personClass.getFields();
        for(Field field : fields){
            System.out.println(field);
        }
        System.out.println("======");

        Field a = personClass.getField("a");
        //獲取成員變量a的值
        Person p = new Person();
        Object value = a.get(p);
        System.out.println(value);
        //設(shè)置成員變量a的值
        a.set(p,"張三");
        System.out.println(p);
        System.out.println("======");

        //Field[] getDeclaredFields():獲取所有的成員變量,不考慮修飾符
        Field[] declaredFields = personClass.getDeclaredFields();
        for(Field declareField : declaredFields){
            System.out.println(declareField);
        }
        //Fiels getDeclaredField(String name)
        Field ad = personClass.getDeclaredField("age");
        //忽略訪問權(quán)限修飾符的安全檢查
        ad.setAccessible(true);//暴力反射
        Object value2 = ad.get(p);
        System.out.println(value2);
    }

獲取構(gòu)造方法:

public static void main(String[] args) throws Exception {
        //0,獲取Person的Class對(duì)象
        Class personClass = Person.class;
        /**
         * 獲取構(gòu)造方法們
         */
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        //創(chuàng)建對(duì)象
        Object person = constructor.newInstance("張三", 23);
        System.out.println(person);
        System.out.println("========");

        //使用空參構(gòu)造器
        Constructor constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
        //創(chuàng)建對(duì)象
        Object person1 = constructor1.newInstance();
        System.out.println(person1);
        //空參構(gòu)造可以使用簡化形式直接用class對(duì)象的newInstance()方法
        Object o = personClass.newInstance();
        System.out.println(o);
    }

獲取成員方法們:
執(zhí)行方法:Object invoke(Object obj, Object... args)
獲取所有public修飾的方法:getMethods();
獲取方法名稱:String getName()

獲取類名:

     //0,獲取Person的Class對(duì)象
        Class personClass = Person.class;
        String className = personClass.getName();
        System.out.println(className);
    }

案例:寫一個(gè)框架,可以幫我們創(chuàng)建任意類的對(duì)象,并且執(zhí)行其中任意方法。
實(shí)現(xiàn):(1)配置文件(2)反射
步驟:
(1)將需要?jiǎng)?chuàng)建的對(duì)象的全類名和需要執(zhí)行的方法定義在配置文件中;
(2)在程序中加載讀取配置文件
(3)使用反射技術(shù)來加載類文件進(jìn)內(nèi)存
(4)創(chuàng)建對(duì)象
(5)執(zhí)行方法
pro.properties文件:

className=cn.itcast.day12.demo01.test.Student
methodName=sleep
/**
 * 框架類
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        /**
         * 前提:不能改變?cè)擃惖娜魏未a
         * 可以創(chuàng)建任意類的對(duì)象,可以執(zhí)行任意方法
         */
        //1,加載配置文件
        //1.1創(chuàng)建Properties對(duì)象
        Properties pro = new Properties();
        //1.2加載配置文件,轉(zhuǎn)換為一個(gè)集合
        //1.2.1獲取class目錄下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        pro.load(is);

        //2,獲取配置文件中定義的數(shù)據(jù)
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        //3,加載該類進(jìn)內(nèi)存
        Class cls = Class.forName(className);

        //4,創(chuàng)建對(duì)象
        Object obj = cls.newInstance();

        //5,獲取方法對(duì)象
        Method method = cls.getMethod(methodName);

        //6,執(zhí)行方法
        method.invoke(obj);
    }
}

三,注解

概念:說明程序的,給計(jì)算機(jī)看的
JDK中預(yù)定義的一些注解:

  • @Override:檢測(cè)該注解標(biāo)注的方法是否是繼承自父類的
  • @Deprecated:該注解標(biāo)注的內(nèi)容表示已過時(shí)
  • @SuppressWarnings:壓制警告
    *一般傳遞參數(shù)all

自定義注解:
格式:元注解
public @interface 注解名稱{
屬性列表;//其實(shí)就是成員方法
}
本質(zhì):注解本質(zhì)上就是一個(gè)接口,該接口默認(rèn)繼承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation{}
屬性:接口中的抽象方法

  • 屬性的返回值類型有下列取值:基本數(shù)據(jù)類型、字符串、枚舉、注解、以上類型的數(shù)組。
  • 定義了屬性,在使用時(shí)需要給屬性賦值:如果定義屬性時(shí),使用default關(guān)鍵字給屬性默認(rèn)初始值,則使用注解時(shí),可以不進(jìn)行屬性的賦值;如果只有一個(gè)屬性需要賦值,并且屬性的名稱是value,則value可以省略,直接定義值即可;數(shù)組賦值時(shí),使用{}包裹,如果數(shù)組中只有一個(gè)值,則大括號(hào)可以省略。
public @interface MyAnno2 {
    int age();
}
@MyAnno2(age = 12)
public class DemoAnnotation {
}

枚舉

public enum Person {
    p1,p2;
}
public @interface MyAnno {  
    Person per();
}
@MyAnno(per = Person.p1)
public class Worker {
}

所有屬性賦值:

public @interface MyAnno {
    Person per();
    MyAnno2 anno2();
    String[] strs();
    int show1();
    String show2();
}
@MyAnno(per = Person.p1,anno2 = @MyAnno2,strs = {"abc", "bbb"},show1 = 1,show2 = "abc")
public class Worker {
}

元注解:用于描述注解的注解
(1)@Target:描述注解能夠作用的位置
ElementType取值:TYPE可以作用于類上;METHOD:可以作用于方法上;FIELD:可以作用于成員變量上

@Target(value={ElementType.TYPE,})//表示該MyAnno2注解只能作用于類上

(2)@Retention:描述注解被保留的階段
@Retention(RetentionPolicy.RUNTIME):當(dāng)前被描述的注解,會(huì)保留到class字節(jié)碼文件中,并被JVM讀取到。
(3)@Documented:描述注解是否被抽取到API文檔中
(4)@Inherited:描述注解是否被子類繼承

在程序使用(解析)注解:獲取注解中定義的屬性值
(1)獲取注解定義位置的對(duì)象(Class,Method,F(xiàn)Ield)
(2)獲取指定的注解:getAnnotation(Class)
(3)調(diào)用注解中的抽象方法獲取配置的屬性值

/**
 * 描述需要執(zhí)行的類名和方法名
 */
@Target({ElementType.TYPE})//可以作用在類上
@Retention(RetentionPolicy.RUNTIME)//希望被保留在RUNTIME階段
public @interface Pro {
    String className();
    String methodName();
}
/**
 * 框架類:前提:不能改變?cè)擃惖娜魏未a,可以創(chuàng)建任意類的對(duì)象,可以執(zhí)行任意方法
 */
@Pro(className = "cn.itcast.day12.demo01.demo06.Demo1",methodName = "show")
public class AnnoTest {
    public static void main(String[] args) throws Exception{
        //1,解析注解
        //1.1獲取該類的字節(jié)碼文件對(duì)象
        Class<AnnoTest> annoTestClass = AnnoTest.class;
        //2,獲取上邊的注解對(duì)象
        //其實(shí)就是在內(nèi)存中生成了一個(gè)該注解接口的子類實(shí)現(xiàn)對(duì)象
        Pro an = annoTestClass.getAnnotation(Pro.class);
        //3,調(diào)用注解對(duì)象中定義的抽象方法,獲取返回值
        String className = an.className();
        String methodName = an.methodName();
        System.out.println(className);
        System.out.println(methodName);

        //3,加載該類進(jìn)內(nèi)存
        Class cls = Class.forName(className);

        //4,創(chuàng)建對(duì)象
        Object obj = cls.newInstance();

        //5,獲取方法對(duì)象
        Method method = cls.getMethod(methodName);

        //6,執(zhí)行方法
        method.invoke(obj);
    }
}

案例:
Check.java

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

Calculator.java

    @Check
    public void add(){
        System.out.println("1+0="+(1+0));
    }

    @Check
    public void sub(){
        System.out.println("1-0="+(1-0));
    }

    @Check
    public void mul(){
        System.out.println("1*0="+(1*0));
    }

    @Check
    public void div(){
        System.out.println("1/0="+(1 / 0));
    }

    public void show(){
        System.out.println("永無bug...");
    }
}

TestCheck.java

/**
 * 簡單的測(cè)試框架
 * 當(dāng)祝方法執(zhí)行后,會(huì)自動(dòng)自行被檢測(cè)的所有方法(加了Check注解的方法),判斷方法是否有異常,記錄到文件中
 */
public class TestCheck {
    public static void main(String[] args) throws IOException {
        //1,創(chuàng)建計(jì)算器對(duì)象
        Calculator c = new Calculator();
        //2,獲取字節(jié)碼文件對(duì)象
        Class cls = c.getClass();
        //3,獲取所有的方法
        Method[] methods = cls.getMethods();

        int num = 0;//出現(xiàn)異常的對(duì)象
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));

        for(Method method : methods) {
            //4,判斷方法上是否有Check注解,有即執(zhí)行
            if (method.isAnnotationPresent(Check.class)) {
                try {
                    method.invoke(c);
                } catch (Exception e) {
                    //5,捕獲異常
                    //記錄到文件中
                    num++;
                    bw.write(method.getName() + "方法出異常了");
                    bw.newLine();
                    bw.write("異常的名稱:" + e.getCause().getClass().getSimpleName());
                    bw.newLine();
                    bw.write("異常的原因:" + e.getCause().getMessage());
                    bw.newLine();
                    bw.write("======");
                }
            }
        }
        bw.write("本次測(cè)試一共出現(xiàn)"+ num +"次異常");
        bw.flush();
        bw.close();

    }
}

執(zhí)行結(jié)果bug.txt

div方法除異常了
異常的名稱:ArithmeticException
異常的原因:/ by zero
======本次測(cè)試一共出現(xiàn)1次異常

小結(jié):
(1)以后大多數(shù)時(shí)候,我們會(huì)使用注解,而不是自定義注解。
(2)注解給誰用?編譯器,解析程序
(3)注解不是程序的一部分,可以理解為注解就是一個(gè)標(biāo)簽。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容