你真的會寫單測嗎?TDD初體驗

前言:

  昨天讀到了一篇文章,講的是TDD,即Test-Driven Development,測試驅動開發。大體意思是,它要求在編寫某個功能的代碼之前先編寫測試代碼,然後只編寫使測試通過的功能代碼,通過測試來推動整個開發的進行。這有助於編寫簡潔可用和高質量的代碼,並加速開發過程。

  初讀之時,瞬間感受到了震撼,感覺和自己之前的開發流程全都不一樣,之前是由始至終,而這種思想確實以終為始。後來一查這種思想早在前幾年甚至前幾十年就被提出了,進而被廣泛運用到了敏捷開發中。看來是自己孤落寡聞了,於是我準備將這種思想用到今後的開發中,要做的第一件事,就是溫習如何寫用例。

為什麼是溫習?

  早在實習的時候,我們研發組就有寫用例的習慣,但是隨着開發逐漸熟悉,這種習慣不知不覺就被丟棄了,有頁面的點點點,沒頁面的看邏輯。相信有很多人也像我一樣,不知不覺就把這項技能丟棄了,接下來就讓我們一起,去重新撿起這項技能。

工具選擇

Junit

對於一個Java開發工程師來說,一提到寫單測,我們最先想到的,一定是Junit。下面是maven坐標

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

用Junit我們可以快速的,簡潔的用註解進行單元測試。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:conf/core/*.xml")
public class ObjTest {

  @Test
  public void testFunc(){
     //todo test          
  }
}

這裏要注意的是@ContextConfiguration註解中的路徑是Spring配置文件的位置。測試的方法必須是public的,且沒有返回值。

mockito

mockito是一個用於模擬對象的工具,我認為他也是測試工作中必不可少的一部分,詳細的介紹我推薦可以看一下:

人生苦短,我用Mockito 

比較不錯的入門案例,它的maven坐標地址為:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

Mock這種測試方法, 對比傳統的Junit測試,有如下好處:

    1. 不用每次測試的是時候,都初始化Spring容器,採用Mock的方式模擬對象,效率高
    2. 對象間的依賴關係,可以用Mock去表達,同時,我們不關心的部分,我們都可以用Mock的方式代替(比如對象A引用對象B的某某方法,但是我們不關係對象B方法實現,只想藉助方法,這個時候就可以Mock)
    3. 可以應對複雜的測試環境,比如方法調用順序、方法調用次數等等。

以下是Mock的一個小案例:

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
    /**
     * mock對象
     */
    @Mock
    List<String> mockedList;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testMock() {
        // mock對象行為
        Mockito.when(mockedList.get(0)).thenReturn("one");
        Assert.assertEquals("one", mockedList.get(0));
        // 僅僅是mock了對象的行為,實際上列表還是空的
        Assert.assertEquals(0, mockedList.size());

        //驗證mock對象的get方法被調用過,且調用時的參數是0
        Mockito.verify(mockedList).get(0);
    }
}

這裡在使用@Mock的時候,必須事先調用MockitoAnnotations.initMocks(this),且使用@RunWith(MockitoJUnitRunner.class)

Jacoco

JaCoCo是一個開源的覆蓋率工具,支持多種覆蓋率的統計,其中包括:

    1. 行覆蓋率:度量被測程序的每行代碼是否被執行,判斷標準行中是否至少有一個指令被執行。
    2. 類覆蓋率:度量計算class類文件是否被執行。
    3. 分支覆蓋率:度量if和switch語句的分支覆蓋情況,計算一個方法裏面的總分支數,確定執行和不執行的 分支數量。
    4. 方法覆蓋率:度量被測程序的方法執行情況,是否執行取決於方法中是否有至少一個指令被執行。
    5. 指令覆蓋:計數單元是單個java二進制代碼指令,指令覆蓋率提供了代碼是否被執行的信息,度量完全 獨立源碼格式。
    6. 圈複雜度:在(線性)組合中,計算在一個方法裏面所有可能路徑的最小數目,缺失的複雜度同樣表示測 試案例沒有完全覆蓋到這個模塊。

下面是它的maven坐標:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

接下來我們用maven插件的方式,對jacoco進行配置

<plugin>
     <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
       <version>0.8.3</version>
       <configuration>
            <includes>
               <include>com/**/*</include>
            </includes>
            <!-- rules裏面指定覆蓋規則 -->
            <rules>
            <rule implementation="org.jacoco.maven.RuleConfiguration">
               <element>BUNDLE</element>
               <limits>  
               <!-- 指定方法覆蓋到50% -->
               <limit implementation="org.jacoco.report.check.Limit">
                   <counter>METHOD</counter>
                   <value>COVEREDRATIO</value>
                   <minimum>0.50</minimum>
                </limit>
                <!-- 指定分支覆蓋到50% -->
                <limit implementation="org.jacoco.report.check.Limit">
                    <counter>BRANCH</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.50</minimum>
                 </limit>
                 <!-- 指定類覆蓋到100%,不能遺失任何類 -->
                 <limit implementation="org.jacoco.report.check.Limit">
                    <counter>CLASS</counter>
                    <value>MISSEDCOUNT</value>
                    <maximum>0</maximum>
                  </limit>
                  </limits>
              </rule>
              </rules>
         </configuration>
         <executions>
             <execution>
                <id>pre-test</id>
                  <goals>
                       <goal>prepare-agent</goal>
                   </goals>
             </execution>
             <execution>
                   <id>post-test</id>
                   <phase>test</phase>
                   <goals>
                       <goal>report</goal>
                   </goals>
             </execution>
       </executions>
  </plugin>

  這裏值得注意的是<include>com/**/*</include>指的是class文件的位置。做完這些以後,我們就可以生成報表了。因為我們是用maven插件的方式進行配置的,所以如果我們使用idea進行開發的時候,就可以看到右側maven一欄中出現了jacoco插件

 最常用的就是這兩個,一個是檢查配置是否正確,第二個是用來將exec文件,生成index.html用來進行觀察覆蓋率。

我們先執行maven中的test指令,這時,我們在target中就可以看到一個jacoco.exec文件。

有了這個jacoco.exec文件,就可以使用jacoco的report方法,來生成文件。

 右鍵index.html文件,選擇Reveal in Finder(Mac),windows也是類似,打開文件磁盤的位置。

 可以看到,由於這個項目之前沒有幾個單測,所以覆蓋率特別低。點開之後,就可以看到具體的代碼,非常的方便。

 最後今天配置jacoco的時候,踩了2個坑:

1 用idea進行開發的同學。使用jacoco的時候,不要勾選這個按鈕,它會跳過你測試階段的代碼執行,進而不會生成jacoco.exec文件。

 

 2 保證自己測試代碼沒有錯誤(尤其是項目中,由於代碼更新,測試用例沒有更新,導致的測試不可用)

這裏的現象是雖然可以生成jacoco.exec 文件,而且可以report成文檔,但是打開之後發現,代碼覆蓋率都是0。

最後:

希望大家都可以保持寫測試用例的好習慣,謝謝

 

 

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

您可能也會喜歡…