走進Java介面測試之構建工具Maven入門

  • 2019 年 11 月 25 日
  • 筆記

前言

Maven 作為一個構建工具,不僅能幫我們自動化構建、自動化測試、還能夠抽象構建過程,提供構建任務實現;它跨平台,對外提供了一致的操作介面,這一切足以使它成為優秀的、流行的構建工具。Maven 不僅是構建工具,還是一個依賴管理工具和項目管理工具,它提供了中央倉庫,能幫助我們自動下載構件。

官網:https://maven.apache.org/

安裝

這裡只介紹 window下如何安裝,在安裝 Maven 之前,先確認已經安裝了 JDK。

接著去下載附件解壓到你想要的目錄就行了。

最後設置一下環境變數,將 Maven 安裝配置到作業系統環境中,主要就是配置 M2_HOMEPATH 兩項,如下圖:

都搞定後,驗證一下,打開 doc 輸入 mvn-v 如何得到下面資訊就說明配置成功了。

主要目錄

  • bin 目錄:包含了 mvn 運行的腳本,這些腳本用來配置 java 命令,準備好 classpath 和相關的 Java 系統屬性,然後執行Java命令;
  • boot 目錄:只包含一個文件,該文件為 plexus-classworlds-2.5.2.jarplexus-classworlds 是一個類載入器框架,相對於默認的 java 類載入器,它提供了更加豐富的語法以方便配置,Maven 使用該框架載入自己的類庫;
  • conf 目錄:包含了一個非常重要的文件 settings.xml。直接修改該文件,就能在機器上全局地訂製 Maven 的行為,一般情況下,我們更偏向於複製該文件至 ~/.m2/ 目錄下(~表示用戶目錄),然後修改該文件,在用戶範圍訂製 Maven 的行為;
  • lib 目錄:包含了所有 Maven 運行時需要的 Java 類庫,Maven 本身是分模組開發的,因此用戶能看到諸如 maven-core-3.0.jarmaven-model-3.0.jar 之類的文件,此外這裡還包含一些 Maven 用到的第三方依賴如 commons-cli-1.2.jarcommons-lang-2.6.jar 等等;

配置加速鏡像

maven 倉庫默認在國外,使用難免很慢,尤其是下載包的時候,換為中國鏡像,讓你感受飛一般的感覺。中國支援 maven 鏡像的有阿里雲,開源中國等,這裡示例阿里雲的。

打開 maven 的配置文件(一般在 maven 安裝目錄的 conf/settings.xml),在 <mirrors></mirrors> 標籤中添加 mirror 子節點(當然也可以在用戶 home 目錄 .m2 下面添加一個 settings.xml 文件)。

<!-- 阿里雲倉庫 --><mirror>    <id>alimaven</id>    <mirrorOf>central</mirrorOf>    <name>aliyun maven</name>    <url>http://maven.aliyun.com/nexus/content/repositories/central/</url></mirror>

以上central 表示該配置為中央庫的鏡像,任何對於中央倉庫的請求都會轉至該鏡像,用戶也可以用同樣的方法配置其他倉庫的鏡像。

這裡介紹下配置的各種選項:

  • <mirrorOf>*<mirrorOf>:匹配所有遠程倉庫;
  • <mirrorOf>external:*<mirrorOf>:匹配所有遠程倉庫,使用 localhost 的除外,使用 file:// 協議的除外。也就是說,匹配所有不在本機上的遠程倉庫;
  • <mirrorOf>repo1,repo2<mirrorOf>:匹配倉庫 repo1h 和 repo2,使用逗號分隔多個遠程倉庫;
  • <mirrorOf>*,!repo1<mirrorOf>:匹配所有遠程倉庫,repo1 除外,使用感嘆號將倉庫從匹配中排除;

需要注意的是,當鏡像倉庫不穩定或者停止服務的時候,Maven 仍將無法訪問被鏡像倉庫,因而將無法下載構件。

與IDEA整合

配置

打開 IDEA,在菜單欄中 File->Settings。然後,在 Settings 對話框中選擇 Build,Execution, Deployment->BuildTools->Maven。

保存即可。

IDEA中使用

新建一個 maven 項目後會在窗口的右端出現一個 Maven Project 按鈕,單擊該按鈕後彈出下圖的對話框:

其中 Lifecycle 中包括了 maven 常用的命令,Dependencies 展示了當前 Maven項目的相關依賴包列表。

簡單介紹下 Maven 的常用命令:

  • mvn clean:表示運行清理操作(會默認把 target 文件夾中的數據清理);
  • mvn clean compile:表示先運行清理之後運行編譯,會將程式碼編譯到 target 文件夾中;
  • mvn clean test:運行清理和測試;
  • mvn cleanpackage:運行清理和打包;
  • mvn clean install:運行清理和安裝,會將打好的包安裝到本地倉庫中,以便其他的項目可以調用;
  • mvn clean deploy:運行清理和發布(發布到私服上面);

上面的命令大部分都是連寫的,大家也可以拆分分別執行,看個人喜好以及使用需求

pom.xml

入門使用

maven 項目的核心是 pom.xml ——POM(Project Object Model 項目對象模型),如下:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.zuozewei</groupId>    <artifactId>springBootDemo1</artifactId>    <version>0.0.1-SNAPSHOT</version>    <name>springBootDemo1</name></project>
  • 程式碼的第一行是 XML 頭,指定了該 XML 文檔的版本和編碼方式;
  • project 是所有 pom.xml 的根元素,它還聲明了一些 POM 相關的命名空間及 xsd 元素
  • 根元素下的第一個子元素 modelVersion 指定了當前的 POM 模型的版本,對於 Maven3 來說,它只能是 4.0.0;
  • 程式碼中最重要是包含了 groupId,artifactId 和 version 了。這三個元素定義了一個項目基本的坐標,在 Maven 的世界,任何的 jar、pom 或者 jar 都是以基於這些基本的坐標進行區分的:
    • groupId:定義了項目屬於哪個組,隨意命名,比如Google公司的myapp項目,就取名為 com.google.myapp;
    • artifactId:定義了當前 Maven 項目在組中唯一的ID,比如定義hello-world。
    • version:指定了項目當前的版本 0.0.1-SNAPSHOT,SNAPSHOT 意為快照,說明該項目還處於開發中,是不穩定的;
    • name:元素生命了一個對於用戶更為友好的項目名稱,雖然這不是必須的,但還是推薦為每個 POM 聲明 name,以方便資訊交流;

依賴的配置

<dependencies>    <dependency>        <groupId>實際項目</groupId>         <artifactId>模組</artifactId>        <version>版本</version>        <type>依賴類型</type>        <scope>依賴範圍</scope>        <optional>依賴是否可選</optional>        <!—主要用於排除傳遞性依賴-->        <exclusions>             <exclusion>                 <groupId>…</groupId>                <artifactId>…</artifactId>            </exclusion>            </exclusions>        </dependency><dependencies>

根元素 project 下的 dependencies 可以包含一個或者多個 dependency 元素,以聲明一個或者多個項目依賴。每個依賴可以包含的元素有:

grounpId、artifactId 和 version: 以來的基本坐標,對於任何一個依賴來說,基本坐標是最重要的,Maven 根據坐標才能找到需要的依賴。

  • type:依賴的類型,對於項目坐標定義的packaging。大部分情況下,該元素不必聲明,其默認值為jar;
  • scope:依賴的範圍;
  • optional:標記依賴是否可選;
  • exclusions:用來排除傳遞性依賴;

如下示例:

dependencies>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>4.12</version>    </dependency>    <dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-test</artifactId>    <version>4.3.14.RELEASE</version>    <scope>test</scope>   </dependency>    <dependency>      <groupId>org.slf4j</groupId>      <artifactId>slf4j-api</artifactId>      <version>${slf4j.version}</version>    </dependency>  </dependencies>

排除依賴

有時候你引入的依賴中包含你不想要的依賴包,你想引入自己想要的,這時候就要用到排除依賴了,比如下圖中 spring-boot-starter-web 自帶了 logback 這個日誌包,我想引入 log4j2 的,所以我先排除掉 logback 的依賴包,再引入想要的包就行了。

排除依賴程式碼結構:

<exclusions>    <exclusion>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-logging</artifactId>    </exclusion></exclusions>

注意:聲明 exclustion 的時候只需要 groupId 和 artifactId,而不需要 version 元素,這是因為只需要 groupId 和 artifactId 就能唯一定位依賴圖中的某個依賴。

歸類依賴

有時候我們引入的很多依賴包,他們都來自同一個項目的不同模組,所以他們的版本號都一樣,這時候我們可以用屬性來統一管理版本號。

<project>      <modelVersion>4.0.0</modelVersion>      <groupId>com.juven.mvnbook.account</groupId>      <artifactId>accout-email</artifactId>      <version>1.0.0-SNAPSHOT</version>      <properties>          <springframework.version>1.5.6</springframework.version>      </properties>      <dependencies>          <dependency>              <groupId>org.springframework</groupId>              <artifactId>spring-core</artifactId>              <version>${springframework.version}</version>          </dependency>           <dependency>              <groupId>org.springframework</groupId>              <artifactId>spring-beans</artifactId>              <version>${springframework.version}</version>          </dependency>             </dependencies>  </project>  

如下所示:

</properties>    這裡定義你先要的版本</properties>

通過以上來定義,然後在下面依賴使用 ${} 來引入你的屬性。

了解倉庫

概念

在 Maven 世界中,任何一個依賴、插件或者項目構建的輸出,都可以稱為構件。得益於坐標機制,任何 Maven 項目使用任何一個構件的方式都是完全相同的。在此基礎上,Maven可以在某個位置統一存儲所有 Maven 項目共享的構件,這個統一的位置就是倉庫。實際的 Maven 項目將不再各自存儲其依賴文件,它們只需要聲明這些依賴的坐標,在需要的時候(例如,編譯項目的時候需要將依賴加入到 classpath 中),Maven 會自動根據坐標找到倉庫中的構件,並使用它們 為了實現重用,項目構建完畢後可生成的構件也可以安裝或者部署到倉庫中,供其他項目使用。

倉庫的布局

任何一個構件都有其唯一的坐標,根據這個坐標可以定義其在倉庫中的唯一存儲路徑,這便是 Maven 的倉庫布局方式。該路經與坐標對應關係為 groupId/artifactId/version/artifactId-version.packaging 舉個例子,比如下面這個分頁插件依賴如下:

 <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>1.2.47</version> </dependency>

那它對應的倉庫的路徑就是這樣:

Maven 倉庫是基於簡單文件系統存儲的,我們也理解其存儲方式、因此,當遇到一些與倉庫相關的問題時,可以很方便的查找相關文件,方便定位問題。

倉庫的分類

本地倉庫

一般來說,在 Maven 項目目錄下,沒有諸如 lib/ 這樣用來存放依賴文件的目錄。當 Maven 在執行編譯或測試時,如果需要使用依賴文件,它總是基於坐標使用本地倉庫的依賴文件。默認情況下,不管在 Window 還是 Linux 下,每個用戶在自己用戶目錄下都有一個路徑名為 .m2/repository/ 的倉庫目錄。如果你想自定義本地倉庫目錄地址。你可以編輯文件 ~/.m2/settings.xml,設置 localRepository 元素的值為想要的倉庫地址,例如:

<settings><localRepository>D:javarepository</localRepository></settings>

複製程式碼這樣,該用戶的本地倉庫地址就被設置成了 D:javarepository 需要注意的是,默認情況下, ~/.m2/settings.xml文件不存在,用戶需要從 Maven 安裝目錄複製 $M2_HOME/conf/settings.xml文件再進行編輯。

遠程倉庫-中央倉庫

由於最原始的本地倉庫是空的,Maven 必須知道至少一個可用的遠程倉庫,才能在執行 Maven 命令的時候下載到需要的構件。中央倉庫就是這樣一個默認的遠程倉庫,Maven 的安裝文件自帶了中央倉庫的配置。中央倉庫包含了這個世界上絕大多數流行的開源 Java 構件,以及源碼、作者資訊、SCM,資訊、許可證資訊等,每個月這裡都會接受全世界 Java 程式設計師大概1億次的訪問,它對全世界 Java 開發者的貢獻由此可見一斑。

遠程倉庫-私服

私服是一種特殊的遠程倉庫,它是架設在區域網內的倉庫服務,私服代理廣域網上的遠程倉庫,供區域網內的 Maven 用戶使用。當 Maven 需要下載構件的時候,它從私服請求,如果私服上不存在該構件,則從外部的遠程倉庫下載,快取在私服上之後,再為 Maven 的下載請求提供服務。因此,一些無法從外部倉庫下載到的構件也能從本地上傳到私服上供大家使用。私服的好處:

  • 節省自己的外網速度;
  • 加速 Maven 構建;
  • 部署第三方構建;
  • 提高穩定性,增強控制;
  • 降低中央倉庫的負荷;

倉庫服務搜索

這裡介紹兩個提供倉庫服務搜索的地址:

  • Sonatype Nexus:https://repository.sonatype.org/
  • MVNrepository:http://mvnrepository.com/

maven test

maven-surefire-plugin

maven 本身並不是一個單元測試框架,maven 做的只是在構建執行到特定生命周期階段的時候,通過插件來執行 Junit 或 TestNG 的測試用例。這插件是 maven-surefire-plugin—測試運行器。

默認情況下, maven-surefire-plugin 的 test 目標會自動執行測試源碼路徑(默認 src/test/java/)下所有符合一組命名模式的測試類如:

**/Test*.java  : 任何子目錄下所有命名以Test開頭的Java類**/*Test.java  :任何子目錄下所有命名以Test結尾的Java類**/*TestCase.java :任何子目錄下所有命名以Test結尾的java類

跳過測試

mvn package-DskipTests

第一種方式:POM中配置 maven-surefire-plugin 插件提供該屬性(一般不推薦):

<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-surefire-plugin</artifactId>    <version>2.5</version>    <configuration>       <skipTests>true</skipTests>    </configuration></plugin>

第二種方式:跳過測試程式碼的編譯:

mvn  package-Dmaven.test.skip=true

參數 maven.test.skip 同時控制了 maven-compiler-pluginmaven-surefire-plugin 兩個插件的行為,測試程式碼編譯跳過,測試運行跳過。

maven.test.skip 的 POM 配置如下:

<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-compiler-plugin</artifactId>    <version>2.5</version>    <configuration>       <skipTests>true</skipTests>    </configuration></plugin> <plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-surefire-plugin</artifactId>    <version>2.5</version>    <configuration>       <skipTests>true</skipTests>    </configuration></plugin>

動態執行運行的測試用例

maven-surefire-plugin 提供一個 test 參數讓用戶能夠在命令行指定要運行的測試用例。

  • mvn test-Dtest=RandomGeneratorTest[測試用例的類名] ——效果是只有需要測試的測試類得到運行;
  • mvn test-Dtest=Random*Test ——運行所有類名以 Random 開頭,Test 結尾的測試類;
  • mvn test-Dtest=test1,test2,test3 ——逗號指定多個測試用例,效用是告訴 maven 運行這些測試類;
  • mvn test-Dtest=test1,test2,test3,Random*Test ——星號和逗號可結合使用;
  • mvn test-Dtest-DfailIfNoTests=false ——效用是告訴 maven-surefire-plugin 即使沒有任何測試也不要報錯,否側maven-surefire-plugin找不到任何匹配的測試類,就會報錯並導致構建失敗;

PS:上述命令行動態指定測試類的方法都應該只是臨時使用,否則失去測試本身意義。

包含與排除測試用例

maven 提倡約定優於配置原則。

maven 自動運行測試:

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.5</version><configuration>    <includes>    <include>**/*Tests.java</include>     </includes></configuration></plugin

通過 excludes 元素排除一些符合默認命名模式的測試類:

<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-surefire-plugin</artifactId>    <version>2.5</version>    <configuration>        <excludes>        <exclude>**/*ServiceTest.java</exclude>        <exclude>**/*TempDaoTest.java</exclude>         </excludes>    </configuration></plugin>

有了excludes 配置後, maven-surefire-plugin 將不再自動運行它們。

小結

本文介紹了 maven 中常用的知識點,希望對大家有所幫助。