優(yōu)雅編程之這樣寫測試用例,你就“正?!绷耍ň牛?/h2>

開心一笑

【朋友病了,要掛鹽水。給他扎針的是一個實(shí)習(xí)小護(hù)士,扎了半天都沒扎進(jìn)血管。
他痛得齜牙咧嘴,無奈叫來了護(hù)士長。
護(hù)士長好手法,只見她一針見血地扎進(jìn)了血管,然后馬上拔出來,
把針遞給那個實(shí)習(xí)護(hù)士說:“看清楚沒有?你再試一次!”】

提出問題

如何優(yōu)雅編寫測試代碼???

解決問題

開發(fā)工作當(dāng)中,我們經(jīng)常需要編寫很多接口,但是往往忽略了單元測試。即使使用了單元測試,對于大部分人來說,也是用過既仍。編寫一些簡潔,可復(fù)用的單元測試時非常有必要的,以下是來自《代碼整潔之道》的幾點(diǎn)總結(jié):

1)TDD(測試驅(qū)動開發(fā)),意思是先寫單元測試,然后寫對應(yīng)的代碼,通過修改調(diào)試讓寫的代碼通過單元測試。使用TDD,會使測試覆蓋所有的代碼,測試代碼和生產(chǎn)代碼的比例有可能會達(dá)到1:1 ,所以也會帶來成本的問題,所有我們要保持測試的整潔。

2)單元測試的好處:讓代碼可擴(kuò)展,可維護(hù),可復(fù)用。

3)整潔測試的三要素 :可讀性、可讀性、可讀性。

4)每個測試都可以拆分為三個環(huán)節(jié):構(gòu)造測試數(shù)據(jù)、操作測試數(shù)據(jù)、檢驗(yàn)操作是否達(dá)到預(yù)期結(jié)果。

5)雙重標(biāo)準(zhǔn):測試環(huán)境中和生產(chǎn)環(huán)境中有些條件不必完全一致。生產(chǎn)環(huán)境中有時要考慮內(nèi)存、CPU等性能問題,而在測試環(huán)境中不必做這些限制。

6)一個測試一個斷言,不必完全糾結(jié),但單個測試斷言數(shù)應(yīng)該最小化,只測試一個概念,還是單一職責(zé)的問題;

7)F.I.R.S.T原則

  • F Fast:測試需要頻繁運(yùn)行,因此要能快速運(yùn)行;

  • I Independent:測試應(yīng)該相互獨(dú)立;

  • R Repeatable:測試應(yīng)當(dāng)能在任何環(huán)境中重復(fù);

  • S Self-validating:自足驗(yàn)證,測試應(yīng)該能看到成功與否的結(jié)果;

  • T Timely:測試應(yīng)該及時編寫,應(yīng)該恰好在生產(chǎn)代碼之前編寫;

下面用一個例子說明上面的理論(理論很枯燥,實(shí)例很美好):

package com.hwy.test;

import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;

public class CodeCleanTest {

    @Test
    public void testBuySnacks(){
        List<String> snacks =  buySnacks();
        Assert.assertEquals("購買零食有問題,請檢查!!!",true,snacks.size()>0);
    }

    @Test
    public void testEatSnacks(){
        /** 這個是我們自己構(gòu)建的零食數(shù)據(jù),肯定不會出現(xiàn)null等問題 **/
        /** 我們不要調(diào)用buySnacks方法,因?yàn)檫€是單一職責(zé)的問題,只測試一個概念**/
        List<String> snacks =  getSnacks();
        Assert.assertEquals("沒有一起吃3個零食", 3, eatSnacks(snacks));
    }

    @Test
    public void testDropLitter(){

        List<String> snacks =  getSnacks();
        Assert.assertEquals("垃圾沒有扔掉!!!",true,dropLitter(snacks));
    }

    @Test
    public void testDateWithGirl() throws Exception{
        Assert.assertEquals("約會失敗了", true, dateWithGirl());
    }

    /**
     * 構(gòu)建零食數(shù)據(jù)(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @return
     */
    public List<String> getSnacks(){
        List<String> snacksList = new ArrayList<>();
        snacksList.add("牛奶");
        snacksList.add("巧克力");
        snacksList.add("土豆片");
        return snacksList;
    }

    /**
     * 買零食(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @return
     */
    public List<String> buySnacks(){
        List<String> snacksList = new ArrayList<>();
        snacksList.add("牛奶");
        snacksList.add("巧克力");
        snacksList.add("土豆片");
        /** 這里故意顯示為空 **/
        //return null;
        return snacksList;
    }

    /**
     * 約會
     */
    public boolean dateWithGirl() throws Exception {
        boolean isSuccess = false;
        List<String> snacksList =  buySnacks();
        /** 利用逆向思維,拋出一個業(yè)務(wù)異常,這里我只是用簡單的exception代替 **/
        if(null == snacksList || snacksList.size() ==0){
            throw new Exception("你沒買到零食或買到的零食有問題,請檢查!");
        }
        /** 代碼執(zhí)行到這一步就說明snacksList不為null,之后的所有
         * 操作都不用判斷snacksList是否為空 **/
        List<String> litter =  eatSnacks(snacksList);
        dropLitter(litter);
        isSuccess = true;
        return isSuccess;
    }



    /**
     * 吃零食(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @param snacks
     */
    public List<String> eatSnacks(List<String> snacks){
        for (String snack : snacks) {
            System.out.println("一起吃" + snack);
        }
        return snacks;
    }

    /**
     * 仍垃圾(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @param litter
     */
    public boolean dropLitter(List<String> litter){
        boolean isDrop = false;
        for(String snack:litter){
            System.out.println("扔掉垃圾:" + snack);

        }
        /** 這里故意寫的有點(diǎn)冗余,只是方便大家學(xué)習(xí) **/
        isDrop = true;
        return isDrop;
    }


}

上面的每個測試方法都是:test + 原方法名稱,一般測試方法都是這么命名的。同時上面的測試方法,每個方法都是獨(dú)立的,只測試一個概念。

下面舉一個錯誤的實(shí)例:

package com.hwy.test;

import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;

public class CodeCleanTest {

    @Test
    public void testBuySnacks() throws Exception{
        /** 像這樣子,在一個測試方法中,測試太多的方法,造成測試用例難以復(fù)用 **/
        /** 這樣不符合每個測試一個斷言的規(guī)則,同時也不符合F.I.R.S.T原則**/
        List<String> snacks =  buySnacks();
        Assert.assertEquals("購買零食有問題,請檢查!!!",true,snacks.size()>0);

        Assert.assertEquals("沒有一起吃3個零食", 3, eatSnacks(snacks));

        Assert.assertEquals("垃圾沒有扔掉!!!",true,dropLitter(snacks));

        Assert.assertEquals("約會失敗了", true, dateWithGirl());
    }


    /**
     * 構(gòu)建零食數(shù)據(jù)(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @return
     */
    public List<String> getSnacks(){
        List<String> snacksList = new ArrayList<>();
        snacksList.add("牛奶");
        snacksList.add("巧克力");
        snacksList.add("土豆片");
        return snacksList;
    }

    /**
     * 買零食(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @return
     */
    public List<String> buySnacks(){
        List<String> snacksList = new ArrayList<>();
        snacksList.add("牛奶");
        snacksList.add("巧克力");
        snacksList.add("土豆片");
        /** 這里故意顯示為空 **/
        //return null;
        return snacksList;
    }

    /**
     * 約會
     */
    public boolean dateWithGirl() throws Exception {
        boolean isSuccess = false;
        List<String> snacksList =  buySnacks();
        /** 利用逆向思維,拋出一個業(yè)務(wù)異常,這里我只是用簡單的exception代替 **/
        if(null == snacksList || snacksList.size() ==0){
            throw new Exception("你沒買到零食或買到的零食有問題,請檢查!");
        }
        /** 代碼執(zhí)行到這一步就說明snacksList不為null,之后的所有
         * 操作都不用判斷snacksList是否為空 **/
        List<String> litter =  eatSnacks(snacksList);
        dropLitter(litter);
        isSuccess = true;
        return isSuccess;
    }



    /**
     * 吃零食(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @param snacks
     */
    public List<String> eatSnacks(List<String> snacks){
        for (String snack : snacks) {
            System.out.println("一起吃" + snack);
        }
        return snacks;
    }

    /**
     * 仍垃圾(事實(shí)這些注釋都是不需要,只是為了大家理解)
     * @param litter
     */
    public boolean dropLitter(List<String> litter){
        boolean isDrop = false;
        for(String snack:litter){
            System.out.println("扔掉垃圾:" + snack);

        }
        /** 這里故意寫的有點(diǎn)冗余,只是方便大家學(xué)習(xí) **/
        isDrop = true;
        return isDrop;
    }


}
感悟

讀書感悟

來自《窮查理智慧書》

  • 忙碌的人們很少有閑客來訪;沸騰的鍋里絕不會落入蒼蠅。
  • 失意時,沒有人了解;得意時,不了解自己。
  • 憤怒總是有一定的理,但很少有好的道理。
  • 你可能有時犯大錯,是因?yàn)槟阏J(rèn)為自己永遠(yuǎn)正確。
  • 一百個小偷,也偷不走一個人的臉皮,特別是當(dāng)這個人沒有臉皮的話。
  • 人們經(jīng)常把自己看錯了,卻很少把自己忘記了。
  • 無人認(rèn)錯的爭吵必然延續(xù)無盡。
  • 如果你的秘密不想被敵人知道,請先對你的朋友保密。
  • 教訓(xùn)換來的一兩智慧,勝過書本一斤的知識。

其他

如果有帶給你一絲絲小快樂,就讓快樂繼續(xù)傳遞下去,歡迎轉(zhuǎn)載,點(diǎn)贊,頂,歡迎留下寶貴的意見,多謝支持!

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

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,234評論 25 708
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,663評論 19 139
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,449評論 4 61
  • 項(xiàng)目史無前例的難找,最近在做明天的計劃,看看有沒有轉(zhuǎn)型的可能 現(xiàn)在的項(xiàng)目是基于easyUI+SSH的框架,好幾個大...
    雁門員外閱讀 245評論 0 0
  • 何謂強(qiáng)求,說白了就是死切白咧求著不屬于自己的東西,然后得不到后嚎啕大哭,怨天尤人,哭訴到:憑什么,到底是憑什么!其...
    cici吃閱讀 458評論 0 2

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