天天看點

maven編寫主代碼與測試代碼

3.2 編寫主代碼 

項目主代碼和測試代碼不同,項目的主代碼會被打包到最終的構件中(比如jar),而測試代碼隻在運作測試時用到,不會被打包。預設情況下,Maven假設項目主代碼位于src/main/java目錄,我們遵循Maven的約定,建立該目錄,然後在該目錄下建立檔案com/juvenxu/mvnbook/helloworld/HelloWorld.java,其内容如代碼清單3-2:

代碼清單3-2:Hello World的主代碼

code:

1 package com.juvenxu.mvnbook.helloworld;  
 2    
 3 public class HelloWorld  
 4 {  
 5    public String sayHello()  
 6    {  
 7      return "Hello Maven";  
 8    }  
 9   
10   public static void main(String[] args)  
11    {  
12      System.out.print( new HelloWorld().sayHello() );  
13    }  
14 }        

 這是一個簡單的Java類,它有一個sayHello()方法,傳回一個String。同時這個類還帶有一個main方法,建立一個HelloWorld執行個體,調用sayHello()方法,并将結果輸出到控制台。

關于該Java代碼有兩點需要注意。首先,在95%以上的情況下,我們應該把項目主代碼放到src/main/java/目錄下(遵循Maven的約定),而無須額外的配置,Maven會自動搜尋該目錄找到項目主代碼。其次,該Java類的包名是com.juvenxu.mvnbook.helloworld,這與我們之前在POM中定義的groupId和artifactId相吻合。一般來說,項目中Java類的包都應該基于項目的groupId和artifactId,這樣更加清晰,更加符合邏輯,也友善搜尋構件或者Java類。

代碼編寫完畢後,我們使用Maven進行編譯,在項目根目錄下運作指令 mvn clean compile ,我們會得到如下輸出:

1 [INFO] Scanning for projects...  
 2 [INFO] ------------------------------------------------------------------------  
 3 [INFO] Building Maven Hello World Project  
 4 [INFO]    task-segment: [clean, compile]  
 5 [INFO] ------------------------------------------------------------------------  
 6 [INFO] [clean:clean {execution: default-clean}]  
 7 [INFO] Deleting directory D:\code\hello-world\target  
 8 [INFO] [resources:resources {execution: default-resources}]  
 9 [INFO] skip non existing resourceDirectory D: \code\hello-world\src\main\resources  
10 [INFO] [compiler:compile {execution: default-compile}]  
11 [INFO] Compiling 1 source file to D: \code\hello-world\target\classes  
12 [INFO] ------------------------------------------------------------------------  
13 [INFO] BUILD SUCCESSFUL  
14 [INFO] ------------------------------------------------------------------------  
15 [INFO] Total time: 1 second  
16 [INFO] Finished at: Fri Oct 09 02:08:09 CST 2009  
17 [INFO] Final Memory: 9M/16M  
18 [INFO] ---------------------      

       clean告訴Maven清理輸出目錄target/,compile告訴Maven編譯項目主代碼,從輸出中我們看到Maven首先執行了clean:clean任務,删除target/目錄,預設情況下Maven建構的所有輸出都在target/目錄中;接着執行resources:resources任務(未定義項目資源,暫且略過);最後執行compiler:compile任務,将項目主代碼編譯至target/classes目錄(編譯好的類為com/juvenxu/mvnbook/helloworld/HelloWorld.Class)。

      上文提到的clean:clean、resources:resources,以及compiler:compile對應了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标,後文會詳細講述Maven插件及其編寫方法。

      至此,Maven在沒有任何額外的配置的情況下就執行了項目的清理和編譯任務,接下來,我們編寫一些單元測試代碼并讓Maven執行自動化測試。

3.3 編寫測試代碼

      為了使項目結構保持清晰,主代碼與測試代碼應該分别位于獨立的目錄中。3.2節講過Maven項目中預設的主代碼目錄是src/main/java,對應地,Maven項目中預設的測試代碼目錄是src/test/java。是以,在編寫測試用例之前,我們先建立該目錄。

     在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事實上的單元測試标準。要使用JUnit,我們首先需要為Hello World項目添加一個JUnit依賴,修改項目的POM如代碼清單3-3:

     代碼清單3-3:為Hello World的POM添加依賴

1 <?xml version="1.0" encoding="UTF-8"?>  
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"  
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0  
 5 http://maven.apache.org/maven-v4_0_0.xsd">  
 6   <modelVersion>4.0.0</modelVersion>  
 7   <groupId>com.juvenxu.mvnbook</groupId>  
 8   <artifactId>hello-world</artifactId>  
 9   <version>1.0-SNAPSHOT</version>  
10   <name>Maven Hello World Project</name>  
11   <dependencies>  
12     <dependency>  
13        <groupId>junit</groupId>  
14        <artifactId>junit</artifactId>  
15        <version>4.7</version>  
16        <scope>test</scope>  
17     </dependency>  
18   </dependencies>  
19 </project>          

        代碼中添加了dependencies元素,該元素下可以包含多個dependency元素以聲明項目的依賴,這裡我們添加了一個依賴——groupId是junit,artifactId是junit,version是4.7。前面我們提到groupId、artifactId和version是任何一個Maven項目最基本的坐标,JUnit也不例外,有了這段聲明,Maven就能夠自動下載下傳junit-4.7.jar。也許你會問,Maven從哪裡下載下傳這個jar呢?在Maven之前,我們可以去JUnit的官網下載下傳分發包。而現在有了Maven,它會自動通路中央倉庫(http://repo1.maven.org/maven2/),下載下傳需要的檔案。讀者也可以自己通路該倉庫,打開路徑junit/junit/4.7/,就能看到junit-4.7.pom和junit-4.7.jar。本書第6章會詳細介紹Maven倉庫及中央倉庫。

       上述POM代碼中還有一個值為test的元素scope,scope為依賴範圍,若依賴範圍為test則表示該依賴隻對測試有效,換句話說,測試代碼中的import JUnit代碼是沒有問題的,但是如果我們在主代碼中用import JUnit代碼,就會造成編譯錯誤。如果不聲明依賴範圍,那麼預設值就是compile,表示該依賴對主代碼和測試代碼都有效。

       配置了測試依賴,接着就可以編寫測試類,回顧一下前面的HelloWorld類,現在我們要測試該類的sayHello()方法,檢查其傳回值是否為“Hello Maven”。在src/test/java目錄下建立檔案,其内容如代碼清單3-4:

       代碼清單3-4:Hello World的測試代碼

1 package com.juvenxu.mvnbook.helloworld;  
 2 import static org.junit.Assert.assertEquals;  
 3 import org.junit.Test;  
 4   
 5 public class HelloWorldTest  
 6 {  
 7     @Test  
 8     public void testSayHello()  
 9     {  
10         HelloWorld helloWorld = new HelloWorld();  
11   
12         String result = helloWorld.sayHello();  
13   
14         assertEquals( "Hello Maven", result );  
15     }  
16 }         

      一個典型的單元測試包含三個步驟:一,準備測試類及資料;二,執行要測試的行為;三,檢查結果。上述樣例中,我們首先初始化了一個要測試的HelloWorld執行個體,接着執行該執行個體的sayHello()方法并儲存結果到result變量中,最後使用JUnit架構的Assert類檢查結果是否為我們期望的”Hello Maven”。在JUnit 3中,約定所有需要執行測試的方法都以test開頭,這裡我們使用了JUnit 4,但我們仍然遵循這一約定,在JUnit 4中,需要執行的測試方法都應該以@Test進行标注。

     測試用例編寫完畢之後就可以調用Maven執行測試,運作 mvn clean test :

1 [INFO] Scanning for projects...  
 2 [INFO] ------------------------------------------------------------------------  
 3 [INFO] Building Maven Hello World Project  
 4 [INFO]    task-segment: [clean, test]  
 5 [INFO] ------------------------------------------------------------------------  
 6 [INFO] [clean:clean {execution: default-clean}]  
 7 [INFO] Deleting directory D:\git-juven\mvnbook\code\hello-world\target  
 8 [INFO] [resources:resources {execution: default-resources}]  
 9 …  
10 Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.pom  
11 1K downloaded  (junit-4.7.pom)  
12 [INFO] [compiler:compile {execution: default-compile}]  
13 [INFO] Compiling 1 source file to D: \code\hello-world\target\classes  
14 [INFO] [resources:testResources {execution: default-testResources}]  
15 …  
16 Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.jar  
17 226K downloaded  (junit-4.7.jar)  
18 [INFO] [compiler:testCompile {execution: default-testCompile}]  
19 [INFO] Compiling 1 source file to D:\ code\hello-world\target\test-classes  
20 [INFO] ------------------------------------------------------------------------  
21 [ERROR] BUILD FAILURE  
22 [INFO] ------------------------------------------------------------------------  
23 [INFO] Compilation failure  
24 D:\code\hello-world\src\test\java\com\juvenxu\mvnbook\helloworld\HelloWorldTest.java:[8,5] -source 1.3 中不支援注釋  
25 (請使用 -source 5 或更高版本以啟用注釋)  
26     @Test  
27 [INFO] ------------------------------------------------------------------------  
28 [INFO] For more information, run Maven with the -e switch  
29   …        

       不幸的是建構失敗了,不過我們先耐心分析一下這段輸出(為了本書的簡潔,一些不重要的資訊我用省略号略去了)。指令行輸入的是mvn clean test,而Maven實際執行的可不止這兩個任務,還有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暫時我們需要了解的是,在Maven執行測試(test)之前,它會先自動執行項目主資源處理,主代碼編譯,測試資源處理,測試代碼編譯等工作,這是Maven生命周期的一個特性,本書後續章節會詳細解釋Maven的生命周期。

      從輸出中我們還看到:Maven從中央倉庫下載下傳了junit-4.7.pom和junit-4.7.jar這兩個檔案到本地倉庫(~/.m2/repository)中,供所有Maven項目使用。

      建構在執行compiler:testCompile任務的時候失敗了,Maven輸出提示我們需要使用-source 5或更高版本以啟動注釋,也就是前面提到的JUnit 4的@Test注解。這是Maven初學者常常會遇到的一個問題。由于曆史原因,Maven的核心插件之一compiler插件預設隻支援編譯Java 1.3,是以我們需要配置該插件使其支援Java 5,見代碼清單3-5:

      代碼清單3-5:配置maven-compiler-plugin支援Java 5

<project>  
…  
  <build>  
    <plugins>  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-compiler-plugin</artifactId>  
         <configuration>  
           <source>1.5</source>  
           <target>1.5</target>  
         </configuration>  
       </plugin>  
    </plugins>  
  </build>  
…  
</project>       
1 …  
 2 [INFO] [compiler:testCompile {execution: default-testCompile}]  
 3 [INFO] Compiling 1 source file to D: \code\hello-world\target\test-classes  
 4 [INFO] [surefire:test {execution: default-test}]  
 5 [INFO] Surefire report directory: D:\code\hello-world\target\surefire-reports  
 6 -------------------------------------------------------  
 7  T E S T S  
 8 -------------------------------------------------------  
 9 Running com.juvenxu.mvnbook.helloworld.HelloWorldTest  
10 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.055 sec  
11 Results :  
12 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0  
13 [INFO] ------------------------------------------------------------------------  
14 [INFO] BUILD SUCCESSFUL  
15 [INFO] ------------------------------------------------------------------------  
16 …