接口自動化測試一體式解決方案(集成:Java+Testng+Maven+Jenkins+ExtentReports+Retrofit2+Git)

接口自動化測試一體式解決方案

前戲叨逼叨:
測試多年工作經(jīng)驗匹层,很少有寫文章极谊、博客之類的東西六敬。
其實我這人不愛去寫博客之類的東西碘赖,更多的是靠腦子的總結(jié)。不是腦子好用外构,其實就一句話:懶普泡!就是懶!I蟊唷撼班!
早在幾年前就有記錄的想法,但當時確實因為工作原因 加上懶垒酬,就借口了自己砰嘁。
好了件炉,如今就要奔三的人,該面對的往往都要面對矮湘。
于是覺得是該寫點東西記錄下斟冕,倒不是說要總結(jié)什么的;只是想讓自己經(jīng)歷過的事情缅阳,通過記錄的形式加強印象磕蛇;與此同時,希望能夠給像自己這樣的小白十办,在遇到類似問題時能夠帶來想法秀撇。
所以,第一次寫類似測試技術(shù)博客向族,獻丑呵燕。看官海涵~
第一篇不談理論件相,實踐篇虏等。
叨逼叨結(jié)束!适肠。

2017.8.17 更新:

  1. 接口實現(xiàn)輔助類的優(yōu)化霍衫。
  2. 因單接口用例數(shù)量上升,多接口的 .xml 文件管理混亂問題侯养,進行優(yōu)化敦跌。
櫻木鎮(zhèn)樓

無聊的背景

測試工作多年,一路以來一直都會伴隨著服務(wù)端的測試逛揩。
那么首當其沖的肯定是接口測試柠傍, 而接口測試中首先聯(lián)想到的是接口自動化測試。
注意:服務(wù)端測試 != 接口測試 != 接口自動化測試 辩稽。這個公式是不等惧笛!找機會再寫篇文章詳細聊聊...
在經(jīng)歷過多中不同的平臺后,毅然而然的覺得通過碼代碼的用例是最靠譜的逞泄。別相信那些帶UI降低編寫接口自動化用例難度的自動化平臺患整,原因不詳!(不想詳細解釋喷众,入坑后自會明白...)
好了各谚,今天介紹一款接口自動化測試的一體式解決方案。(有點夸張到千,其實吧還真是一體式昌渤。)這是入坑后,個人認為在Java大背景服務(wù)開發(fā)下比較理想的解決方案憔四。
最后膀息,接口自動化測試的框架和平臺形形色色般眉,不用評論哪個好,哪個差潜支。只有最合適項目團隊的才是最好的甸赃。(廢話...)

本文代碼github:https://github.com/Jsir07/TestHub

話不多說,先上Jenkins上自助運行用例毁腿,查看報告流程截圖辑奈。也可結(jié)合持續(xù)集成自動觸發(fā)測試服務(wù)苛茂。
Jenkins自助運行流程

一已烤、方案介紹

①. 選型:Java + Maven + Testng + ExtentReports + Git + Retrofit2 + Jenkins

  • 使用Java作為項目編程語言。
  • 使用Maven作為項目類型妓羊,方便管理架包胯究。
  • 使用TestNG作為項目運行框架,方便執(zhí)行測試用例躁绸,生成測試報告裕循。
  • 使用ExtentReports作為代替TestNG報告的報告驅(qū)動,二次美化功能净刮,界面更美觀剥哑,內(nèi)容清晰
  • 使用Git作為倉庫管理工具,方便管理項目代碼淹父。
  • 使用Retrofit2作為API接口自動化項目底層服務(wù)驅(qū)動框架株婴。
  • 使用Jenkins作為自動化持續(xù)集成平臺,方便自動編譯暑认,自動打包困介,自動運行測試腳本,郵件發(fā)送測試報告蘸际,通知等座哩。

②. 功能介紹:

  1. 實現(xiàn)持續(xù)集成測試,自助式測試粮彤,一站式測試平臺根穷。
  2. 通過Retrofit2作為等常用接口定義與請求方法壁晒,使用方便簡潔减宣。同時可分離接口定義鸭廷、實現(xiàn)請求互躬、響應(yīng)驗證友扰。
  3. 參數(shù)化驅(qū)動用例運行方式泌霍,目前使用本地配置文件梆靖;可擴展為造數(shù)據(jù)嵌纲。
  4. 還有...自己體會...

二闯两、環(huán)境安裝與配置

(一)開發(fā)環(huán)境:

  1. JDK1.7 及以上
  2. IDEA 社區(qū)版(壕->pro)
  3. Maven 不限
  4. Git 不限
  5. Jenkins 不限

(二)部分環(huán)境安裝細節(jié):

1. JDK 安裝請查閱褥伴。https://www.cnblogs.com/ottox/p/3313540.html
2. Maven 安裝與配置谅将。
  • setting配置,主要是國內(nèi)鏡像 阿里云重慢。https://blog.csdn.net/liuhui_306/article/details/52822152
    - 加速饥臂。

    <mirror>
          <id>alimaven</id>
          <name>aliyun maven</name>
          <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
          <mirrorOf>central</mirrorOf>        
    </mirror>
    
    
  • 本地localRepository配置。為什么要配置這個似踱?因為默認是放在C盤的隅熙。Default: ${user.home}/.m2/repository。jar 太多核芽、太大囚戚!

    <localRepository>E:\apache-maven-3.5.3\repository</localRepository>
    
  • 命令配置。https://www.cnblogs.com/eagle6688/p/7838224.html
    - 為啥配置這個轧简?因為后面Jenkins如果需要在本地運行的話驰坊,需要用到mvn命令。

3. IDEA 安裝請查閱哮独,下載社區(qū)版本即可拳芙。 https://www.jetbrains.com/idea/
4. Git 安裝。

參考:https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git

5. Jenkins本地安裝惨寿,只要安裝不用創(chuàng)建任務(wù)邦泄,后面會有任務(wù)創(chuàng)建。

參考:https://www.cnblogs.com/c9999/p/6399367.html裂垦。

若遇網(wǎng)站需要翻墻顺囊,具體下載安裝請自行百度。

三蕉拢、框架搭建

(一) 項目基礎(chǔ)工程

搭工程特碳,建立基本工程框架,采用maven結(jié)構(gòu)框架工程晕换。 話不多說午乓,先搭建工程。方式:

1.1 IDEA 上闸准,F(xiàn)ile ->New ->Project -> maven. 選maven后益愈,不選任何模板,直接Next。
image.png
1.2 填寫對應(yīng)項目信息后蒸其,next敏释。
image.png
1.3 繼續(xù)填寫 對應(yīng)信息后,F(xiàn)inish摸袁。
image.png

(二)Maven pom.xml文件配置 與多環(huán)境切換

2.1 依賴配置

需要使用到的依賴有testng钥顽、extentreports、retrofit靠汁、fastjson蜂大、okhttp等..

 <dependencies>
    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.47</version>
    </dependency>
    
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>3.10.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor  日志攔截器-->
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>logging-interceptor</artifactId>
        <version>3.10.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.testng/testng -->
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>6.14.2</version>
        <!--<scope>test</scope>-->
        <!--作用范圍,默認是test蝶怔。驗證部分被抽象奶浦,不僅test作用域需使用-->
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/com.aventstack/extentreports -->
    <dependency>
        <groupId>com.aventstack</groupId>
        <artifactId>extentreports</artifactId>
        <version>3.1.5</version>
        <scope>provided</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.vimalselvam/testng-extentsreport -->
    <dependency>
        <groupId>com.vimalselvam</groupId>
        <artifactId>testng-extentsreport</artifactId>
        <version>1.3.1</version>
    </dependency>
    
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>retrofit</artifactId>
        <version>2.4.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson 對象轉(zhuǎn)換器-->
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>converter-gson</artifactId>
        <version>2.3.0</version>
    </dependency>
</dependencies>
2.2 配置多環(huán)境切換部分

采用maven環(huán)境切換方式。

  • 2.2.1 先配置pom.xml文件的 build節(jié)點添谊。

    <build>
       <resources>
           <resource>
               <directory>src/main/resources</directory>
               <filtering>true</filtering>
               <!--掃描替換參數(shù)的文件路徑-->
           </resource>
       </resources>
       <filters>
           <filter>src/main/filters/filter-${env}.properties</filter>
           <!--環(huán)境過濾器的配置方式财喳,回頭需要在該路徑下建立對應(yīng)文件-->
       </filters>
       <plugins>
           <plugin>
               <!--該插件是解決命令下執(zhí)行mvn test指定testng xxx.xml 文件 的配置-->
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-surefire-plugin</artifactId>
               <version>2.22.0</version>
               <configuration>
                   <!--為了解決在jenkins maven執(zhí)行test 報告亂碼問題察迟,編碼格式設(shè)置為UTF-8-->
                   <argLine>-Dfile.encoding=UTF-8</argLine>
                   <encoding>UTF-8</encoding>
                   <!--動態(tài)指定執(zhí)行的xml文件斩狱。${project.basedir}項目目錄,${xmlFileName}maven文件-->
                   <suiteXmlFiles>
                       <suiteXmlFile>${project.basedir}/target/classes/testNg/${xmlFileName}</suiteXmlFile>
                   </suiteXmlFiles>
               </configuration>
           </plugin>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <configuration>
                   <encoding>UTF-8</encoding>
                   <source>8</source>
                   <target>8</target>
               </configuration>
           </plugin>
       </plugins>
    </build>
    
  • 2.2.2 在pom.xml文件配置properties為了maven打包編譯時后臺一直輸出警告信息扎瓶。導致構(gòu)建失敗所踊。

        <!--為了maven打包編譯時后臺一直輸出警告信息。導致構(gòu)建失敗-->
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <xmlFileName></xmlFileName>
        </properties>
    
  • 2.2.3 在pom.xml文件配置Properties環(huán)境概荷。多環(huán)境配置參數(shù)切換秕岛。

        <profiles>
            <!-- 開發(fā)環(huán)境,默認激活 -->
            <profile>
                <id>dev</id>
                <properties>
                    <env>dev</env>
                </properties>
            </profile>
    
            <!-- 生產(chǎn)環(huán)境 -->
            <profile>
                <id>product</id>
                <properties>
                    <env>product</env>
                </properties>
            </profile>
    
            <!-- 測試環(huán)境 -->
            <profile>
                <id>debug</id>
                <properties>
                    <env>debug</env>
                </properties>
                <activation>
                    <activeByDefault>true</activeByDefault><!--默認啟用的是dev環(huán)境配置-->
                </activation>
            </profile>
        </profiles>
    
2.3 配置環(huán)境切換-文件部分
  • 2.3.1 在src/resource下創(chuàng)建env.properties文件误证。
    該文件記錄的信息是跟環(huán)境切換相關(guān)的參數(shù)继薛。
    如:接口請求不同環(huán)境的host,mongodb愈捅、mysql數(shù)據(jù)庫等遏考,因不同環(huán)境的信息。
    例如:
        api.post.host=${api.post.host}
    
  • 2.3.2 創(chuàng)建src/main/filters/下創(chuàng)建
    filter-debug.properties蓝谨、filter-dev.properties灌具、filter-product.properties
    用于環(huán)境信息記錄。
    詳細信息譬巫,如:
        api.post.host=http://apidebug.xxx.com:80/
    

如圖:

image.png

(三) testNg配置部分

3.1. 在src/resources/下創(chuàng)建testNg目錄.

src/resources/testNg 目錄是存放測試集合的目錄咖楣,可根據(jù)測試模塊創(chuàng)建對應(yīng)模塊文件夾。

3.1.1 每個文件夾可以是獨立模塊芦昔,每個模塊下可以有模塊的測試集合诱贿。
  • 例如,在src/resources/testNg/下創(chuàng)建測試集合:api/search/search-TestSuite.xml咕缎。配置如下:
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
    
    <suite name="search_tags-搜索分類-電影首頁測試集合" verbose="1" preserve-order="true">
      <parameter name="report.config" value="src/main/resources/config/report/extent-config.xml"/>
      <parameter name="system.info" value="reporter.config.MySystemInfo"/>
    
      <test name="0100.搜索分類-電影首頁-正常場景" preserve-order="true">
        <classes>
            <class name="com.jxq.douban.SearchTagsTest">
                <methods>
                    <include name="testcase1"/>
                </methods>
            </class>
        </classes>
      </test>
    
      <test name="0100.搜索分類-TV首頁-正常場景" preserve-order="true">
        <classes>
            <class name="com.jxq.douban.SearchTagsTest">
                <methods>
                    <include name="testcase2"/>
                </methods>
            </class>
        </classes>
      </test>
    
      <listeners>
        <listener class-name="reporter.Listener.MyExtentTestNgFormatter"/>
      </listeners>
    </suite>
    
3.1.2.為了能夠讓所有接口統(tǒng)一運行測試珠十,需建立一個所有的測試集合咸作,測試集合一般放在src/resources/testNg 目錄下。

型如:

  <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

  <suite name="接口測試集合" verbose="1" preserve-order="true">
    <parameter name="report.config" value="src/main/resources/config/report/extent-config.xml"/>
    <parameter name="system.info" value="reporter.config.MySystemInfo"/>

    <suite-files>
      <suite-file path="search/SearchTags-TestSuite.xml"/>
    </suite-files>

    <listeners>
        <listener class-name="reporter.Listener.MyExtentTestNgFormatter"/>
    </listeners>
    </suite>
3.1.3 說明
  • 有同學會問:為什么會有這么多inclde name宵睦?
    原因是:test里的name是針對一整個testclass的名稱记罚,為了讓每一個測試名稱都能夠展示。
    故此把層級調(diào)整了壳嚎。調(diào)整后的層級對應(yīng)如下:
testng層級 接口映射關(guān)系
test 接口具體的testcase
suite 具體接口所有用例集合
總suite 所有接口測試集合

需要說明的是桐智,在testng接口層級管理上,每個項目可以有各自的方式烟馅,只要符合你的是好的说庭。

  • 這里添加了parameter、listener郑趁,是用于替換testng默認報告刊驴,使用ExtentReported。關(guān)于ExtentReported后面會有說明寡润。
    <parameter name="report.config" value="src/main/resources/config/report/extent-config.xml"/>
    <parameter name="system.info" value="reporter.config.MySystemInfo"/>
    
    <listeners>
        <listener class-name="reporter.Listener.MyExtentTestNgFormatter"/>
    </listeners>

(四) TestCase測試用例

4.1 Test用例類
  • 首先捆憎,滿足maven工程結(jié)構(gòu)在src/test目錄下建立對應(yīng)的測試用例類。
  • 其次梭纹,測試用例類的命名也滿足maven在單元測試時的規(guī)范躲惰。類名以Test結(jié)尾.如:SearchTagsTest.java
  • 最后,根據(jù)各模塊分類建立對應(yīng)模塊包变抽。
4.2 測試用例怎么寫础拨?

其實網(wǎng)上有很多關(guān)于TestNg的文章,這邊就不做過多介紹了绍载。

官網(wǎng):https://testng.org/doc/index.html
也可查閱:https://www.yiibai.com/testng/

寫接口用例诡宗,不在與形式,形式網(wǎng)上很多击儡。
最重要的是編寫的層次與心得塔沃。回頭有空再整理下曙痘。

(五) extentreports報告

extentreports是什么芳悲?網(wǎng)上有很多關(guān)于使用extentreports替代TestNg自帶報告。原因是什么边坤?
漂亮名扛。先上張圖。


官網(wǎng)很重要:http://extentreports.com/. 其實官網(wǎng)已經(jīng)給了很多demo了茧痒,這里我根據(jù)自己的經(jīng)驗進行了配置肮韧。

testNg原有報告有點丑,信息整理有點亂。ExtentReports是用于替換testNg原有的報告弄企。也可以使用ReportNg超燃,個人偏好ExtentReports樣式。

5.1 強制重寫ExtentTestNgFormatter類

強制重寫EExtentTestNgFormatter類主要是以下兩點原因:
①拘领、為了能夠在報告中展示更多狀態(tài)類型的測試結(jié)果意乓,例如:成功、失敗约素、警告届良、跳過等測試狀態(tài)結(jié)果。
②圣猎、因為不支持cdn.rawgit.com訪問士葫,故替css訪問方式。

方式如下:下載ExtentReportes源碼送悔,找到ExtentTestNgFormatter類慢显。

  • 5.1.1 在創(chuàng)建類:src/main/java/reporter/listener路徑下MyExtentTestNgFormatter.java類。
    MyExtentTestNgFormatter直接從ExtentTestNgFormatter繼承欠啤。

    public class MyExtentTestNgFormatter extends ExtentTestNgFormatter {
    
  • 5.1.2 構(gòu)造方法加入htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
    MyExtentTestNgFormatter 類荚藻,代碼如下:

      public MyExtentTestNgFormatter() {
          setInstance(this);
          testRunnerOutput = new ArrayList<>();
          String reportPathStr = System.getProperty("reportPath");
          File reportPath;
    
          try {
              reportPath = new File(reportPathStr);
          } catch (NullPointerException e) {
              reportPath = new File(TestNG.DEFAULT_OUTPUTDIR);
          }
    
          if (!reportPath.exists()) {
              if (!reportPath.mkdirs()) {
                  throw new RuntimeException("Failed to create output run directory");
              }
          }
    
          File reportFile = new File(reportPath, "report.html");
          File emailReportFile = new File(reportPath, "emailable-report.html");
    
          htmlReporter = new ExtentHtmlReporter(reportFile);
          EmailReporter emailReporter = new EmailReporter(emailReportFile);
          reporter = new ExtentReports();
          //        如果cdn.rawgit.com訪問不了,可以設(shè)置為:ResourceCDN.EXTENTREPORTS或者ResourceCDN.GITHUB
          htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
          reporter.attachReporter(htmlReporter, emailReporter);
      }
    
  • 5.1.3 接著在onstart方法重寫功能跪妥。
    用了很粗暴的方式鞋喇,新建了一個類名為MyReporter声滥,一個靜態(tài)ExtentTest的引用眉撵。

    • ① reporter.Listener包下MyReporter.java

          public class MyReporter {
              public static ExtentTest report;
          }
      
    • ② MyExtentTestNgFormatter.java

          public void onStart(ITestContext iTestContext) {
              ISuite iSuite = iTestContext.getSuite();
              ExtentTest suite = (ExtentTest) iSuite.getAttribute(SUITE_ATTR);
              ExtentTest testContext = suite.createNode(iTestContext.getName());
              // 將MyReporter.report靜態(tài)引用賦值為testContext。
              // testContext是@Test每個測試用例時需要的落塑。report.log可以跟隨具體的測試用例纽疟。另請查閱源碼。
              MyReporter.report = testContext;
              iTestContext.setAttribute("testContext", testContext);
          }
      
  • 5.1.4 順帶提一句憾赁,測試報告默認是在工程根目錄下創(chuàng)建test-output/文件夾下污朽,名為report.html、emailable-report.html龙考◇∷粒可根據(jù)各自需求在構(gòu)造方法中修改。

        public MyExtentTestNgFormatter() {
            setInstance(this);
            testRunnerOutput = new ArrayList<>();
            // reportPath報告路徑
            String reportPathStr = System.getProperty("reportPath");
            File reportPath;
    
            try {
                reportPath = new File(reportPathStr);
            } catch (NullPointerException e) {
                reportPath = new File(TestNG.DEFAULT_OUTPUTDIR);
            }
    
            if (!reportPath.exists()) {
                if (!reportPath.mkdirs()) {
                    throw new RuntimeException("Failed to create output run directory");
                }
            }
            // 報告名report.html
            File reportFile = new File(reportPath, "report.html");
            // 郵件報告名emailable-report.html
            File emailReportFile = new File(reportPath, "emailable-report.html");
    
            htmlReporter = new ExtentHtmlReporter(reportFile);
            EmailReporter emailReporter = new EmailReporter(emailReportFile);
            reporter = new ExtentReports();
            reporter.attachReporter(htmlReporter, emailReporter);
        }
    
  • 5.1.5 順帶再提一句晦款,report.log 可以有多種玩法炎功。

    // 根據(jù)狀態(tài)不同添加報告。型如警告
    MyReporter.report.log(Status.WARNING, "接口耗時(ms):" + String.valueOf(time));
    

    直接從TestClass中運行時會報MyReporter.report的空指針錯誤缓溅,需做個判空即可蛇损。

5.2 導入MyExtentTestNgFormatter監(jiān)聽類

在測試集合.xml文件中導入Listener監(jiān)聽類。

<listeners>
        <listener class-name="reporter.Listener.MyExtentTestNgFormatter"/>
</listeners>
5.3 配置報告信息

extent reporters支持報告的配置。目前支持的配置內(nèi)容有title淤齐、主題等股囊。

  • 先在src/resources/目錄下添加 config/report/extent-config.xml。

    • 配置內(nèi)容
    <?xml version="1.0" encoding="UTF-8"?>
    <extentreports>
        <configuration>
            <timeStampFormat>yyyy-MM-dd HH:mm:ss</timeStampFormat>
            <!-- report theme -->
            <!-- standard, dark 個人喜好暗色 -->
            <theme>dark</theme>
    
            <!-- document encoding -->
            <!-- defaults to UTF-8 -->
            <encoding>UTF-8</encoding>
    
            <!-- protocol for script and stylesheets -->
            <!-- defaults to https -->
            <protocol>https</protocol>
    
            <!-- title of the document -->
            <documentTitle>QA-接口自動化測試報告</documentTitle>
    
            <!-- report name - displayed at top-nav -->
            <reportName>QA-接口自動化測試報告</reportName>
    
            <!-- report headline - displayed at top-nav, after reportHeadline -->
            <reportHeadline>接口自動化測試報告</reportHeadline>
    
            <!-- global date format override -->
            <!-- defaults to yyyy-MM-dd -->
            <dateFormat>yyyy-MM-dd</dateFormat>
    
            <!-- global time format override -->
            <!-- defaults to HH:mm:ss -->
            <timeFormat>HH:mm:ss</timeFormat>
    
            <!-- custom javascript -->
            <scripts>
                <![CDATA[
            $(document).ready(function() {
    
            });
          ]]>
            </scripts>
    
            <!-- custom styles -->
            <styles>
                <![CDATA[
    
          ]]>
            </styles>
        </configuration>
    </extentreports>
    
5.4 添加系統(tǒng)信息

不多說更啄,上圖稚疹。


可用于添加系統(tǒng)信息,例如:db的配置信息祭务,人員信息贫堰,環(huán)境信息等。根據(jù)項目實際情況添加待牵。
  • 在src/main/java/reporter/config目錄下創(chuàng)建MySystemInfo.java類其屏,繼承SystemInfo接口。

    public class MySystemInfo implements SystemInfo {
        @Override
        public Map<String, String> getSystemInfo() {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("env.properties");
            Properties properties = new Properties();
            Map<String, String> systemInfo = new HashMap<>();
            try {
                properties.load(inputStream);
                systemInfo.put("environment", properties.getProperty("Environment"));
                systemInfo.put("sqlURL", properties.getProperty("ESsql.URL"));
                systemInfo.put("redisHost", properties.getProperty("redis.host"));
                systemInfo.put("redisPort", properties.getProperty("redis.port"));
                systemInfo.put("mongodbHost", properties.getProperty("mongodb.host"));
                systemInfo.put("mongodbPort", properties.getProperty("mongodb.port"));
                systemInfo.put("測試人員", "jxq");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return systemInfo;
        }
    }
    

    至此缨该,extentreports美化報告完成偎行。

(六). retrofit2.0--Http接口測試驅(qū)動原力

其實Java的Http客戶端有很多,例如HTTPClient贰拿、OKHttp蛤袒、retrofit等。膨更。妙真。
為什么那么多Http客戶端會選擇retrofit?用一個圖見證他的實力

如此多的星星可知

真正的原因
接口定義與實現(xiàn)分離
retrofit2.0可將Http接口定義與請求實現(xiàn)分離荚守;通過制定interface定義接口珍德。
網(wǎng)上有很多關(guān)于retrofit2.0的教程,這里就不再班門弄斧了矗漾,度娘即可锈候。參考:https://blog.csdn.net/carson_ho/article/details/73732076

附上本項目方式。

6.1 具體Http Api的定義interface敞贡。新建ISearch interface泵琳。
public interface ISearch {
    @GET("j/search_tags")
    Call<MovieResponseVO> searchTags(@Query("type") String type, @Query("source") String source);
}
6.2 HttpBase基礎(chǔ)類提供原動力。

HttpBase類中提供了Retrofit基礎(chǔ)誊役。
同時获列,我考慮到了日常控制臺和測試報告上都需要看到對應(yīng)請求信息蛔垢,故此在HttpClient中默認加入了日志攔截器击孩;日志攔截器的實現(xiàn)方法里,用Reportes.log記錄到日志中啦桌。
并且溯壶,考慮到實際項目中每個Http請求都會有對應(yīng)類似RequestHeader及皂、RequestBody的加密簽名等,預留了攔截器且改。
可在HttpBase構(gòu)造方法時傳入對應(yīng)攔截器验烧。
對應(yīng)的攔截器可以通過實現(xiàn)接口Interceptor,做對應(yīng)項目需求操作又跛。
先看代碼碍拆。

public class HttpBase {
    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private Retrofit retrofit;
    private String host;

    /**
     * 構(gòu)造方法(1個參數(shù))
     * 只傳Host,默認沒有使用攔截器慨蓝。
     *
     * @param host 訪問域名host
     */
    public HttpBase(String host) {
        init(host, null);
    }

    /**
     * 構(gòu)造方法(2個參數(shù))
     * 只傳Host感混,默認使用日志攔截器。
     *
     * @param host        訪問域名host
     * @param interceptor 自定義攔截器
     */
    public HttpBase(String host, Interceptor interceptor) {
        init(host, interceptor);
    }

    /**
     * 初始化方法
     *
     * @param host        訪問域名host
     * @param interceptor 自定義攔截器
     */
    private void init(String host, Interceptor interceptor) {
        OkHttpClient.Builder client = getHttpClient(interceptor);
        retrofit = new Retrofit.Builder()
                .baseUrl(host)
                .client(client.build())
                .addConverterFactory(RespVoConverterFactory.create())
                .build();
    }

    /**
     * 獲取HttpClient.Builder 方法礼烈。
     * 默認添加了弧满,基礎(chǔ)日志攔截器
     *
     * @param interceptor 攔截器
     * @return HttpClient.Builder對象
     */
    private OkHttpClient.Builder getHttpClient(Interceptor interceptor) {
        HttpLoggingInterceptor logging = getHttpLoggingInterceptor();
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);
        if (interceptor != null) {
            builder.addInterceptor(interceptor);
        }
        builder.addInterceptor(logging);
        return builder;
    }

    /**
     * 日志攔截器
     *
     * @return
     */
    private HttpLoggingInterceptor getHttpLoggingInterceptor() {
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Reporter.log("RetrofitLog--> " + message, true);
            }
        });
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);//Level中還有其他等級. 設(shè)置打印內(nèi)容級別到Body。
        return logging;
    }

    /**
     * retrofit構(gòu)建方法
     *
     * @param clazz 泛型類
     * @param <T>   泛型類
     * @return 泛型類
     */
    public <T> T create(Class<T> clazz) {
        return retrofit.create(clazz);
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }
}
6.3 集成HttpBase的Http Api接口請求方法類

這里需要說明下此熬,為什么需要有這個類的存在庭呜?
其實在Retrofit已經(jīng)可以用4行的代碼實現(xiàn)Http請求了,如下:

        HttpBase httpBase = new HttpBase(host);
        ISearch iSearch = httpBase.create(ISearch.class);
        Call<MovieResponseVO> call = iSearch.searchTags(type, source);
        Response<MovieResponseVO> response = call.execute();

看了上面的4行代碼犀忱,每次都需要寫也是挺麻煩的募谎。
所以抽出來,讓編寫測試用例驗證更簡潔點阴汇。
抽取后的代碼如下:

public class HttpSearch extends HttpBase {
    private ISearch iSearch;

    public HttpSearch(String host) {
        super(host);
        iSearch = super.create(ISearch.class);
    }

    public Response<MovieResponseVO> searchTags(String type, String source) throws IOException {
        Call<MovieResponseVO> call = iSearch.searchTags(type, source);
        return call.execute();
    }

//    同模塊下数冬,新增的接口可添加到這里。
//    public Response<MovieResponseVO> searchTags(String type, String source) throws IOException {
//        Call<MovieResponseVO> call = iSearch.searchTags(type, source);
//        return call.execute();
//    }
}
6.4 使用JsonSchema驗證基礎(chǔ)響應(yīng)體

Http響應(yīng)體非Json格式搀庶,可跳過該步驟拐纱。

這里引入了JsonSchema來做基礎(chǔ)驗證,減少了Http響應(yīng)返回帶來的大量對象基礎(chǔ)驗證地来。
方式如下:

  • 6.4.1 pom.xml 依賴引入
      <!--json schema start-->
      <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-core</artifactId>
          <version>2.9.6</version>
      </dependency>

      <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.6</version>
      </dependency>

      <dependency>
          <groupId>com.github.fge</groupId>
          <artifactId>json-schema-validator</artifactId>
          <version>2.2.6</version>
      </dependency>
      <!--json schema end-->
  • 6.4.2 簡單抽象JsonSchemaUtils工具類戳玫。
    直接看代碼。
/**
* JsonSchema工具類
*/
public class JsonSchemaUtils {
  /**
   * 從指定路徑讀取Schema信息
   *
   * @param filePath Schema路徑
   * @return JsonNode型Schema
   * @throws IOException 拋出IO異常
   */
  private static JsonNode readJSONfile(String filePath) throws IOException {
      InputStream stream = JsonSchemaUtils.class.getClassLoader().getResourceAsStream(filePath);
      return new JsonNodeReader().fromInputStream(stream);
  }

  /**
   * 將Json的String型轉(zhuǎn)JsonNode類型
   *
   * @param str 需要轉(zhuǎn)換的Json String對象
   * @return 轉(zhuǎn)換JsonNode對象
   * @throws IOException 拋出IO異常
   */
  private static JsonNode readJSONStr(String str) throws IOException {
      return new ObjectMapper().readTree(str);
  }

  /**
   * 將需要驗證的JsonNode 與 JsonSchema標準對象 進行比較
   *
   * @param schema schema標準對象
   * @param data   需要比對的Schema對象
   */
  private static void assertJsonSchema(JsonNode schema, JsonNode data) {
      ProcessingReport report = JsonSchemaFactory.byDefault().getValidator().validateUnchecked(schema, data);
      if (!report.isSuccess()) {
          for (ProcessingMessage aReport : report) {
              Reporter.log(aReport.getMessage(), true);
          }
      }
      Assert.assertTrue(report.isSuccess());
  }

  /**
   * 將需要驗證的response 與 JsonSchema標準對象 進行比較
   *
   * @param schemaPath JsonSchema標準的路徑
   * @param response   需要驗證的response
   * @throws IOException 拋出IO異常
   */
  public static void assertResponseJsonSchema(String schemaPath, String response) throws IOException {
      JsonNode jsonSchema = readJSONfile(schemaPath);
      JsonNode responseJN = readJSONStr(response);
      assertJsonSchema(jsonSchema, responseJN);
  }
}

這里已經(jīng)將最后抽成簡單方法供使用未斑,只需傳入schemaPath路勁、以及需要驗證的對象币绩。

  • 6.4.3 Http響應(yīng)體保存到本地
    • ①蜡秽、可以通過客戶端抓包獲取得到Http響應(yīng)體、或者開發(fā)接口定義文檔 等方式缆镣,得到最后Http響應(yīng)體的Json對象芽突。(注意:響應(yīng)體內(nèi)容盡量全面,這樣在驗證時也可以盡可能驗證)
    • ②董瞻、將請求響應(yīng)體通過 https://jsonschema.net/ 寞蚌,在線驗證得到JsonSchema信息田巴。
    • ③、根據(jù)接口響應(yīng)需求挟秤,做基礎(chǔ)驗證配置壹哺。例如,這里將tags字段認為是必須存在的參數(shù)艘刚。
      完整Schema約束文件如下管宵,并將此文件保存到resources目錄對應(yīng)模塊下。
  {
  "$id": "http://example.com/example.json",
  "type": "object",
  "properties": {
    "tags": {
      "$id": "/properties/tags",
      "type": "array",
      "items": {
        "$id": "/properties/tags/items",
        "type": "string",
        "title": "The 0th Schema ",
        "default": "",
        "examples": [
          "熱門",
          "最新"
        ]
      }
    }
  },
  "required": [
    "tags" 
  ]
}
6.5 TestCase測試用例編寫攀甚。
public class SearchTagsTest {
    private static Properties properties;
    private static HttpSearch implSearch;
    private static String SCHEMA_PATH = "parameters/search/schema/SearchTagsMovie.json";

    @BeforeSuite
    public void beforeSuite() throws IOException {
        InputStream stream = this.getClass().getClassLoader().getResourceAsStream("env.properties");
        properties = new Properties();
        properties.load(stream);
        String host = properties.getProperty("douban.host");
        implSearch = new HttpSearch(host);
        stream = this.getClass().getClassLoader().getResourceAsStream("parameters/search/SearchTagsParams.properties");
        properties.load(stream);
        stream = this.getClass().getClassLoader().getResourceAsStream("");
        stream.close();
    }

  // 注意!!! @Test 注釋內(nèi)加入了description 用于描述該測試用例箩朴,(例如:描述測試目標,對象秋度,參數(shù)炸庞,業(yè)務(wù)流程,測試方法等...)
    @Test(description = "電影首頁荚斯。類別:type=movie source=index")
    public void testcase1() throws IOException {
        String type = properties.getProperty("testcase1.req.type");
        String source = properties.getProperty("testcase1.req.source");
        Response<MovieResponseVO> response = implSearch.searchTags(type, source);
        MovieResponseVO body = response.body();
        Assert.assertNotNull(body, "response.body()");
//        響應(yīng)返回內(nèi)容想通過schema標準校驗
        JsonSchemaUtils.assertResponseJsonSchema(SCHEMA_PATH, JSONObject.toJSONString(body));
//        再Json化成對象
        Assert.assertNotNull(body.getTags(), "tags");
    }

    @Test(threadPoolSize = 10, invocationCount = 100, invocationTimeOut = 3, description = "Tv首頁燕雁。類別:type=tv source=index")
    public void testcase2() throws IOException {
        String type = properties.getProperty("testcase2.req.type");
        String source = properties.getProperty("testcase2.req.source");
        Response<MovieResponseVO> response = implSearch.searchTags(type, source);
        MovieResponseVO body = response.body();
        Assert.assertNotNull(body, "response.body()");
        JsonSchemaUtils.assertResponseJsonSchema(SCHEMA_PATH, JSONObject.toJSONString(body));
        Assert.assertNotNull(body.getTags(), "tags");
    }
}

至此,TestNg測試用例部分全部完成鲸拥。

四拐格、Jenkins部分配置

Jenkins的安裝上面已有說明,這里不重復刑赶。

(一) Jenkins插件

1.插件列表

需要使用到的插件有:

  • Maven Integration plugin
  • HTML Publisher plugin
  • Dingding[釘釘] Plugin
  • TestNG Results
  • Groovy
  • Parameterized Trigger Plugin
2. Jenkins插件安裝

怎么安裝插件捏浊?
Jenkins-》系統(tǒng)管理-》插件管理-》搜索插件-》安裝即可

3. 插件說明
  • Maven Integration plugin -必備!
    Maven構(gòu)建插件撞叨,使用簡單方便金踪。

  • HTML Publisher plugin -必備!
    extentreporets美化報告替換testng就是為了好看牵敷,但要在jenkins中展示必須安裝此插件胡岔。

  • Groovy -必備!
    Jenkins不支持異類樣式CSS枷餐,所以Groovy插件是為了解決HTML Publisher plugin在展示extentreporets時能夠正確美麗的作用靶瘸。

  • Dingding[釘釘] Plugin -必備!
    測試用例構(gòu)建結(jié)果的通知毛肋。網(wǎng)上很多說用郵件怨咪,說實話使用場景最頻繁高效的應(yīng)該是IM靠譜。這個插件就是解決測試結(jié)果的通知润匙。

  • TestNG Results - 非必備
    TestNg測試結(jié)果收集诗眨,統(tǒng)計運行結(jié)果數(shù)據(jù)。

  • Parameterized Trigger Pl ugin - 非必備
    依賴構(gòu)建傳參插件孕讳。http://note.youdao.com/noteshare?id=c56333317d3078b36b2479fdf8fe68d7&sub=wcp1530172849180570

(二)Jenkins新建任務(wù)配置

在插件安裝完后匠楚,開始任務(wù)的新建配置巍膘。

  • 新建一個maven項目。


    image.png

(三)General配置

  • 丟棄舊的構(gòu)建配置 -可配
    該配置根據(jù)需求配置芋簿。


    image.png

(四) 構(gòu)建配置-maven配置

在Jenkins使用Maven構(gòu)建項目自動化測試前峡懈,先通過本地使用maven測試是否通過。
這里本來要將參數(shù)化構(gòu)建益咬,但參數(shù)化構(gòu)建前先說明下是如何利用maven構(gòu)建測試的逮诲。

    1. 檢查pom.xml配置中指定的suiteXmlFile對象。
    <suiteXmlFiles>
        <!--用于根據(jù)maven傳入的文件幽告,運行maven test測試集合對象梅鹦。 ${xmlFileName}是maven命令替換對象,別忘了添加properties中的xmlFileName-->
        <suiteXmlFile>${project.basedir}/target/classes/testNg/${xmlFileName}</suiteXmlFile>
        
        <!--在IEDA上運行maven test命令時冗锁,可打開該注釋使用完整測試集合-->
        <!--<suiteXmlFile>${project.basedir}/target/classes/testNg/api/testng.xml</suiteXmlFile>-->
    </suiteXmlFiles>
    
    <properties>
        <xmlFileName></xmlFileName>
    </properties>
    
    1. 先在IDEA上驗證maven test是否生效齐唆?

    <suiteXmlFile>${project.basedir}/target/classes/testNg/api/testng.xml</suiteXmlFile> 開啟后,使用maven test驗證是否成功冻河。如下圖:

image.png
    1. 通過terminal命令驗證maven test是否生效
    • 在2.3.1驗證通過后箍邮,pom.xml注釋<suiteXmlFile>${project.basedir}/target/classes/testNg/api/testng.xml</suiteXmlFile>.
    • 打開<suiteXmlFile>${project.basedir}/target/classes/testNg/${xmlFileName}</suiteXmlFile>
    • 進入terminal命令驗證maven test是否生效。在命令行上輸入mvn clean test -DxmlFileName=testng.xml
    • 驗證maven test 是否正確叨叙。
    image.png
    1. 嘮叨編碼問題

    我在執(zhí)行上面的命令時锭弊,maven一直提示警告信息-編碼問題鬓椭;該警告信息原先我本不太在意胧辽,因為配置沒有問題。
    可后來疙挺,命令執(zhí)行一直報錯钮呀〗0埃看了報錯信息都指向了非編碼問題。也就把我引向了其他錯誤解決區(qū)域爽醋。
    不得不說蚁署,maven的提示還是要重頭到尾認真看。因為真正報錯誤的地方不一定是[error]提示蚂四。
    警告信息是: [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!

    如何解決該問題呢光戈?在pom.xml上加入如下配置。

    // 這個配置由于被誤刪了证杭,導致花費了半天解決田度。。解愤。
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <xmlFileName></xmlFileName>
    </properties>
    

(五) 配置構(gòu)建-maven配置信息。

回到Jenkins界面配置maven信息乎莉。

  • 5.1 先在Jenkins新建任務(wù)送讲,構(gòu)建模塊奸笤,增加構(gòu)建步驟 - 調(diào)用頂層maven目標。
    (需要注意下哼鬓,這里寫的是中文监右,根據(jù)不同的Jenkins版本該名稱可能是英文的)

  • 5.2 然后配置信息如下。在目標加入命令信息:clean test -P%env% -DxmlFileName=%xmlFileName%


  • 5.3命令解釋:clean test -P%env% -DxmlFileName=%xmlFileName%

  • maven參數(shù)化替換使用的占位符是 %xxx%
  • -P%env% 指定maven運行的環(huán)境异希,該環(huán)境信息與pom.xml 配置的信息一直健盒。同時,-P%env% 用于參數(shù)化構(gòu)建傳參使用称簿,后面會有介紹扣癣。
  • -DxmlFileName=%xmlFileName% 指定maven test 運行的測試集合對象。用于參數(shù)化構(gòu)建傳參使用憨降,后面介紹父虑。

(六) 參數(shù)化構(gòu)建過程 配置

  • 6.1添加參數(shù) 選擇是 【選項參數(shù)】。


  • 6.2完整配置信息如下圖授药。


  • 6.3參數(shù)名稱xmlFileName士嚎,對應(yīng)maven構(gòu)建中的-DxmlFileName=%xmlFileName%,再對應(yīng)pom.xml中的<suiteXmlFile>${project.basedir}/target/classes/testNg/${xmlFileName}</suiteXmlFile>
    加入需要運行的集合選項悔叽。

  • 6.4 同樣莱衩,env對應(yīng)maven構(gòu)建中的 -P%env% ,再對應(yīng)pom.xml中的build信息娇澎。
    加入運行的環(huán)境選項笨蚁。

(七) 源碼管理配置

這個配置網(wǎng)上有很多詳細文檔,這里不重復九火。具體度娘查看赚窃。


image.png

(八) 構(gòu)建觸發(fā)器

> 這個配置可根據(jù)實際項目需求配置。個人建議: 接口自動化測試中的自動化最核心的是結(jié)合持續(xù)構(gòu)建岔激。   
> 所以建議配置“其他工程構(gòu)建后觸發(fā)”勒极,填入所需測試的服務(wù)端項目名稱即可。當然要在一個Jenkins中虑鼎。
image.png

(九) 構(gòu)建信息配置

> 上面已經(jīng)配置了“調(diào)用頂層Maven目標”辱匿,然后還需要配置Groovy script。  
> 配置Groovy script的目的是讓Http Reported插件css能用炫彩,同時不用擔心jenkins重啟匾七。
  • 配置Groovy script前保障Groovy 插件已經(jīng)安裝。

  • 增加構(gòu)建步驟“Execute system Groovy script” 江兢,選擇Groovy command昨忆,填入System.setProperty("hudson.model.DirectoryBrowserSupport.CSP", "")

(十) 構(gòu)建后操作信息配置

9.1. publish html reports
加入publish html reports步驟。
- HTML directory to archive: 報告路徑杉允。 填寫extentreports默認輸出路徑:test-output\
- Index page[s] : 報告索引名稱邑贴。填寫extentreports默認報告名稱:report.html
- Keep past HTML reports: 保留報告席里,勾選!不多說拢驾。
9.2 publish html reports
publish testng results 配置奖磁。默認**/testng-results.xml 即可。 
為什么要testng默認報告繁疤? 因為需要統(tǒng)計分析時查看咖为。 當然這個是可選的。
image.png
9.3. 釘釘通知器配置
怎么玩轉(zhuǎn)釘釘消息稠腊?查看https://blog.csdn.net/workdsz/article/details/77531802
- 填入access token躁染。
image.png
4. 構(gòu)建后操作信息配置 釘釘通知器配置 二次開發(fā) - 可選
http://www.51testing.com/html/25/n-3723525.html

(十一) 構(gòu)建測試

  • 11.1 build with parameters


  • 11.2 構(gòu)建成功后 在 HTML Report上查看



  • 11.3 構(gòu)建成功后 在 TestNG Results上查看


  • 11.4 構(gòu)建成功后 在 釘釘上查看


五、工程目錄講解 與 接口測試用例編寫步驟

(一) 工程目錄講解

 先上圖說明

(二) 接口測試用例編寫步驟

1. 目標:具體Htpp接口定義的熟悉麻养、理解褐啡。

注意:Http 請求行、請求頭鳖昌、請求體备畦;響應(yīng)行、響應(yīng)頭许昨、響應(yīng)體

  • 可通過查看開發(fā)wiki文檔懂盐,或者通過抓包等手段達到。
2. 具體Htpp接口的定義 - Host
  • 2.1 將不同環(huán)境的Host地址配置在env.properties文件
  • 2.2 然后在根據(jù)不同環(huán)境糕档,配置不同properties文件莉恼,中對應(yīng)的host信息。filter-debug.properties速那、filter-dev.properties俐银、filter-product.properties。
3. 具體Htpp接口的定義 - interface
  • 3.1 在src/main/java/下com.xxx.api.下新建對應(yīng)模塊端仰,例如article
    • 一個模塊文件夾下存放:接口定義的interface捶惜、接口定義的實現(xiàn)類。
  • 3.2 在article下新建具體的接口定義interface
    public interface IArticle {
      @POST("article/feed")
      Call<ResponseBody> articleFeed(@Query("tid") String tid, @Body RequestBody requestBody);
    }
    
4. 具體Htpp接口的定義實現(xiàn) - implement
  • 4.1 在article下新建具體的接口定義實現(xiàn)

為什么要有這個類荔烧?
原因有1.簡化接口調(diào)用代碼吱七,直接通過靜態(tài)方法調(diào)用。 2. 當遇到接口需要特殊處理時鹤竭,可通過該類進行擴展踊餐。

public class ImplArticle extends HttpBase {
  private IArticle iArticle;

  public ImplArticle(String host) {
      super(host);
      iArticle = super.create(IArticle.class);
  }

  public Response<ResponseBodyVo> articleFeed(String tid, String requestBody) throws IOException {
      Call<ResponseBodyVo> call = iArticle.articleFeed(tid, RequestBody.create(HttpBase.JSON, requestBody));
      return call.execute();
  }
}
5. 編寫測試用例 -xxxTest
  • 5.1 在test/java 目錄下新建對應(yīng)測試模塊的文件夾 ,例如:article

    • 一個接口用例類臀稚,對應(yīng)一個文件夾吝岭。
  • 5.2 在test/java/article 目錄下新建測試用例類。

    • 開始編寫接口測試類。
    public class ArticleFeedTest {
      private static String HOST;
      private static Properties properties;
    
      @BeforeSuite
      public void beforeSuite() throws IOException {
          InputStream stream = this.getClass().getClassLoader().getResourceAsStream("env.properties");
          properties = new Properties();
          properties.load(stream);
          HOST = properties.getProperty("api.newsapi.host");
          stream = this.getClass().getClassLoader().getResourceAsStream("parameters/api/article/ArticleFeedParam.properties");
          properties.load(stream);
          stream.close();
      }
    
      @Test(description = "獲取推薦文章信息流(下拉方式)")
      public void testcase1() throws IOException {
          String reques = properties.getProperty("testcase1.requestBody");
    
          String response = ImplArticle.articleFeed(HOST, "tid", reques);
          ResponseBodyVo responseBodyVo = JSONObject.parseObject(response, ResponseBodyVo.class);
          assertResponseBody(responseBodyVo);
      }
    
    

// 注解 @Test 中的描述信息苍碟,最后可以在報告中體現(xiàn)酒觅。
@Test(description = "獲取推薦文章信息流(上拉方式)")
public void testcase2() throws IOException {
String reques = properties.getProperty("testcase1.requestBody");

    String response = ImplArticle.articleFeed(HOST, "tid", reques);
    ResponseBodyVo responseBodyVo = JSONObject.parseObject(response, ResponseBodyVo.class);
    assertResponseBody(responseBodyVo);
}

}

  
##### 6. 具體接口測試用例suite集合制作
- 在testNg/api/article/ArticleFeed-TestSuite.xml下創(chuàng)建suite集合

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="article/feed-接口測試集合" verbose="1" preserve-order="true">
<parameter name="report.config" value="src/main/resources/config/report/extent-config.xml"/>
<parameter name="system.info" value="reporter.config.MySystemInfo"/>

<test name="ArticleFeedTest接口測試集合" preserve-order="true">
    <classes>
        <class name="com.api.article.ArticleFeedTest"/>
    </classes>
</test>

<listeners>
    <listener class-name="reporter.Listener.MyExtentTestNgFormatter"/>
</listeners>

</suite>


##### 7. 所有接口測試用例suite集合制作    
- 在testNg/api/APICollection-TestSuite.xml下創(chuàng)建suite集合

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="接口測試集合" verbose="1" preserve-order="true">
<parameter name="report.config" value="src/main/resources/config/report/extent-config.xml"/>
<parameter name="system.info" value="reporter.config.MySystemInfo"/>

<suite-files>
    <suite-file path="article/ArticleFeed-TestSuite.xml"/>
    <suite-file path="post/PostFeed-TestSuite.xml"/>
    <suite-file path="push/RegisterToken-TestSuite.xml"/>
    <suite-file path="sys/SysGetConfig-TestSuite.xml"/>
    <suite-file path="sys/SysGetRegions-TestSuite.xml"/>
    <suite-file path="registerDevice/RegisterDevice-TestSuite.xml"/>
</suite-files>

<listeners>
    <listener class-name="reporter.Listener.MyExtentTestNgFormatter"/>
</listeners>

</suite>

 
#### 寫在最后
其實撮执,接口自動化測試平臺的搞起來不難微峰。
推動平臺接入到持續(xù)集成,將測試變成一種服務(wù)抒钱,更快更及時的服務(wù)于項目蜓肆,才是重點。
正所謂:wiki一定谋币,開發(fā)未動仗扬,接口已行。
而蕾额,服務(wù)端測試才挑戰(zhàn)早芭。知識儲備的深度決定了,測試的深度诅蝶。

個人GitHub:  https://github.com/Jsir07/TestHub
歡迎Watch + Fork
end...
  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末退个,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子调炬,更是在濱河造成了極大的恐慌语盈,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缰泡,死亡現(xiàn)場離奇詭異刀荒,居然都是意外死亡,警方通過查閱死者的電腦和手機棘钞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門缠借,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宜猜,你說我怎么就攤上這事泼返。” “怎么了宝恶?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵符隙,是天一觀的道長。 經(jīng)常有香客問我垫毙,道長霹疫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任综芥,我火速辦了婚禮丽蝎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己屠阻,他們只是感情好红省,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著国觉,像睡著了一般吧恃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上麻诀,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天痕寓,我揣著相機與錄音,去河邊找鬼蝇闭。 笑死呻率,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的呻引。 我是一名探鬼主播礼仗,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼逻悠!你這毒婦竟也來了元践?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蹂风,失蹤者是張志新(化名)和其女友劉穎卢厂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惠啄,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡慎恒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了撵渡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片融柬。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖趋距,靈堂內(nèi)的尸體忽然破棺而出粒氧,到底是詐尸還是另有隱情,我是刑警寧澤节腐,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布外盯,位于F島的核電站,受9級特大地震影響翼雀,放射性物質(zhì)發(fā)生泄漏饱苟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一狼渊、第九天 我趴在偏房一處隱蔽的房頂上張望箱熬。 院中可真熱鬧,春花似錦、人聲如沸城须。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糕伐。三九已至砰琢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赤炒,已是汗流浹背氯析。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留莺褒,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓雪情,卻偏偏與公主長得像遵岩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子巡通,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容