寫了一個月的單元測試,總算明白大學里這門課白學了


  上大學的時候學過軟件測試這門課,但是在公司實習時才真正實戰了一把。先花了半個月把Junit In Action 英文版看完了(話說在公司學習效率就是比學校里高啊) 廢話不多說,直接開始主題。

  為什么要寫單元測試?

  兩個理由:1.給我們重構的信心(give us the confidence to refactor)。一堆糾纏而無測試的代碼你敢隨便修改?

       2.好的單元測試就是文檔(documenting expected behavior)。幾個實用的例子比文檔讓人感興趣的多。

  

  概念就不說了,黑盒白盒TDD,語句路徑覆蓋率,網上都有,直接講講我的收獲吧。

  

  我在項目里最初就是給一些基礎類(EntityModel)寫測試,它是一個抽象類,內部保存Entity,並執行增刪改查的操作。那么我第一個遇到的問題就是:如何測試一個抽象類?方法很簡單,就是去定義一個子類,然后生成子類的實例做測試。拿測試update函數來說,有三個步驟:

  1.准備一個Entity,給他設置兩個屬性,age = 10,weight = 50。

  2.把它add進EntityModel,進行update操作,修改他的weight = 80。

  3.最后get出來,驗證得到的Entity weight = 80 且 age = 10。

  代碼如下:

  @Test
    public void testUpdateEntityWhenNotTheSameProperty() {

        MyEntity myEntity = createMyEntity(AGE_ID, WEIGHT_ID, 0L);
        entityModel.addEntity(myEntity);
        entityModel.updateEntity(myEntity.getClass(), myEntity.getId(), MyEntity.PROPERTY_NAME_AGE, DIFF_AGE_ID);
        assertEquals(DIFF_AGE_ID, myEntity.getAge());
    }

  而這三個步驟總結起來就是"准備-構建-驗證"(《clean code》 , Unit Test chapter),測試用例都遵從這個步驟。

  寫着寫着,你會遇到一些問題。怎么驗證我的函數里面調用了一個靜態方法去記錄log日志?怎么驗證一個私有方法?怎么測試一個接口?怎么測試向一個數據庫插入數據的操作?怎么驗證我測試的程序一定會拋出一個異常?……這下就要到網上去查了,有許多現成的框架可供使用,大名鼎鼎的Junit;Mockito可以模擬接口,模擬函數返回值,驗證方法調用次數;Powermock(查看需翻牆)可以模擬靜態方法和final方法;Java的反射機制可以模擬私有方法。

  給函數起名也有講究。我一般用test__when__thenReturn__的結構,盡量讓看的人不用看代碼就能知道功能。

  不能為了省事而把不同性質的驗證放在一個test中,一次只做一件事,做好一件事。

  而且最重要的是,在寫單元測試過程中,我慢慢就對代碼的邏輯清楚了。如果必須要覆蓋每個判斷,等我寫完測試用例,我就已經知道這個函數的每個細節。這對於以后重構很有幫助。

  

  寫的不多,但是我要堅持寫下去,因為總結和思考的過程就是成長。

——周五晚在公司

   

--------------------------------------------

  今天又學到一招,mock過靜態方法的朋友知道,需要在類前添加

@RunWith(PowerMockRunner.class)
@PrepareForTest(xxx.class)

  而如果我需要在一個類中驗證兩個不同類的靜態方法,只需要

@PrepareForTest({Hello.class, World.class})
或是
@PrepareForTest(fullyQualifiedNames = {"com.util.log4j.LogManager","com.rcm.model.risk.defs.BettingFamilies"})

——2015/2/2

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM