使用 soapUI 測試 REST 服務


REST 服務介紹

REST(Representational State Transfer)是 Roy Fielding 博士在 2000 年提出的一種新的軟件架構風格,它以資源(resource)為核心,使用 HTTP、 URI、XML 以及 HTML 等現有流行協議和標准來完成對資源的操作及顯示。 這些操作包括獲取、創建、修改和刪除資源,分別對應於 HTTP 協議的 GET、POST、PUT 和 DELETE 方法。REST 架構定義了以下設計准則:

  • 網絡中的所有事物都被抽象為資源(resource)。
  • 每個資源對應一個唯一的資源標識(resource identifier)。
  • 通過通用的連接器接口(generic connector interface)對資源進行操作。
  • 對資源的各種操作不會改變資源標識。
  • 所有的操作都是無狀態的(stateless)。

REST 服務(RESTful Service)是一種基於 HTTP 和 REST 准則的輕量級 Web 服務。這類服務可以看作一系列資源(resource)的集合,服務的定義可以視為以下三個切面的組合 :

  • 訪問 Web Service 的 URI,如:http://example.com/resources。
  • Web Service 所支持的數據 MIME 類型,如:JSON, XML, YAML 等。
  • Web Service 使用 HTTP 協議支持的操作,如 GET, POST, PUT, DELETE。

相比目前流行的 Web 服務實現方案 SOAP 和 XML-RPC, REST 服務更加簡潔,它可以完全通過 HTTP 協議實現,還可以利用緩存 Cache 來提高響應速度, 其性能,效率和易用性等方面均優於 SOAP 協議。 本文主要介紹如何使用 soapUI 來測試此類 Web 服務。

 

soapUI 介紹

由於 Web 服務是被程序調用的, 一般不會提供界面讓最終用戶或測試人員直接使用,在 soapUI 等工具出現之前,測試人員不得不自己編寫程序來測試它, 這就要求測試人員花費很大的精力了解底層的接口,調用關系和詳細的協議,導致他們不能把注意力集中到測試中。

soapUI 的出現極大的改變了這一局面。 作為一個開源的工具,soapUI 強大的功能、易用的界面,吸引了很多用戶。用戶可以在 soapUI 中通過簡單的操作完成復雜的測試,不需要了解底層的細節, 極大的減輕了工作量。soapUI 支持多樣的測試, 例如功能測試,性能測試,回歸測試等。到目前為止 soapUI 的下載量已經超過了 100 萬次,成為了事實的 Web 服務測試標准和領先的 Web 服務測試工具。 它不僅僅可以測試基於 SOAP 的 Web 服務,也可以測試 REST 風格的 Web 服務,后者也是本文介紹的重點。

soapUI 基於 Java 開發,支持多個平台,安裝非常簡單。讀者可以到 soapUI 的 官方網站下載一個安裝包 ( 本文使用的是 Window 版本 3.0.1),直接安裝即可。在該安裝包中,包括了一個 soapUI 所需要的 JRE1.6 版本。安裝完畢以后,讀者需要設置 JAVA_HOME 變量指向到相應的 JRE 目錄,同時修改 PATH 變量,將 JRE1.6 的 bin 目錄添加進去。

 

REST 服務案例

為了避免空洞的講解,同時為了更好的展示 soapUI 對 REST 服務的測試功能,本文假想了一個在線書店 (http://www.example.com) 的例子。該在線書店對外提供了一些 REST 服務讓第三方的應用程序調用。 為了讓讀者把注意力集中在使用 soapUI 進行測試上,我們對這些 REST 服務進行了必要的簡化,僅僅只包含下面 3 種功能:書籍列表,書籍詳情和添加評論。這 3 個 REST 服務覆蓋了層次狀的 REST 資源、基本的 HTTP 操作和多種展現形式。

服務名稱 HTTP 操作 資源 URI 資源展現 注釋
書籍列表 GET http://www.example.com/books application/json,text/xml 該 REST 服務的目的是列出在線書店中的書籍列表,參見 代碼清單 1和 代碼清單 2
書籍詳情 GET http://www.example.com/books/<book id > application/json 該 REST 服務目的是給定一個書籍 ID,返回該書籍的詳細信息,參見 代碼清單 3,需要注意的是書籍詳細信息是一個帶有層次結構的 json 展示
添加評論 POST http://www.example.com/books/<book id >/comments 無 , 系統僅僅返回 200 OK 該 REST 服務的目的是對一個書籍添加評論,調用方需要 POST 類似 author=xxx&content=xxx 的數據到服務器端。
清單 1. 書籍列表 application/json
 {"books": [ 
   {"book":    { 
      "id": "1234", 
      "name": "book1", 
      "price": 29 
   }}, 
   {"book":    { 
      "id": "5678", 
      "name": "book2", 
      "price": 18 
   }} 
 ]}
清單 2. 書籍列表 text/xml
 <bookes> 
   <book> 
      <id>1234</id> 
      <name>book1</name> 
      <price>29.0</price> 
   </book> 
   <book> 
      <id>5678</id> 
      <name>book2</name> 
      <price>18</price> 
   </book> 
 </bookes>
清單 3. 書籍詳情 application/json
 { 
   "id": "1234", 
   "name": "book1", 
   "description": "this is book 1", 
   "author": "author1", 
   "price": 29, 
   "comments":    [ 
      {"comment":       { 
         "user": "user1", 
         "content": "good book"
      }}, 
      {"comment":       { 
         "user": "user2", 
         "content": "not bad"
      }} 
   ] 
 }
 

在 soapUI 中建立測試用例

基本概念

在創建測試用例之前,我們先來看一看在 soapUI 中的基本概念,soapUI 把 REST 服務、資源及其操作組織為一個層次結構。如 圖 1所示,主要包括如下層次:

  • 項目定義:位於最上層 (BookStoreTest),項目可以包含多個服務的定義。
  • REST 服務定義:服務其實是對多個 REST 資源的一個分組,在我們的例子中只有一個服務 BookStoreServie
  • REST 資源定義:具體描述該資源的名稱,URI, 參數等屬性
  • REST 方法定義:針對每個資源的方法 (GET,POST,PUT,DELETE 等 ),圖 1 中的方法名就是 GetBookList
  • REST 操作請求定義:基於每個方法,可以有一個或多個請求操作,如 GetBookListRequest,這些請求操作才是真正被 soapUI 所調用執行的。每個請求可以設置非常豐富的信息,例如 Accept 類型,請求的 Header 信息,運行了該請求以后,就能以各種方式查看運行結果。但是這里還不能加入斷言來驗證結果 - 必須在建立測試用例以后才能使用。

注: 讀者可以在 下載區的 bookstore-soapui-project.zip 找到完整的例子,下文中主要以該例子為基礎進行講解。讀者解壓 zip 文件以后,能得到一個 xml 文件,可以通過 soapUI 的 File->import project 把項目導入到自己的工作區中。

圖 1. soapUI 中的層次結構

soapUI 中的層次結構

對於測試用例來講,同樣是一個層次結構:

  • TestSuite:類似於 Junit 中的測試套件,其中可以加入多個 TestCase
  • TestCase:可以包含多個 TestStep
  • TestStep:一個 TestCase 可以包含多個 TestStep,TestStep 有多種類型,它可以是上面提到一個 REST 操作請求,也可以是一個 Groovy 的腳本,還可以試一個設置屬性的操作。 TestStep 甚至支持分支跳轉操作:根據特定的條件,從一個 step 可以跳轉到其他 step, 而不必順序執行。

soapUI 實際上是一個平台,它支持強大的編程能力,開發或者測試人員可以利用 groovy 腳本來訪問 soapUI 中的對象,在運行時修改 REST request/response, 這就提供了極大的靈活性。

圖 2. TestCase 定義

TestSuite

創建測試用例

有了上面的基本概念以后,在 soapUI 中創建測試用例就比較簡單了, 用戶幾乎可以根據自己的直覺來一步一步的完成一個測試。圖 3展示的就是一個建立書籍列表 REST 服務的步驟:

1. 新建一個名為 BookStoreTest 的項目 
2. 在項目上點擊右鍵,選擇"New Rest Service",在對話框中輸入 Service Name(BookStoreService) 和 Endpoint(http://localhost:9080)
3. 在"BookstoreService"上點擊右鍵,選擇“New Resource”, 在對話框中輸入 Resource Name(BookList) 和 Resource Path (/books),點擊 OK 
4. 在彈出的對話框中輸入 Method Name: GetBookList,HTTP Method 選擇默認的 GET, 點擊 OK

圖 3. 創建一個 REST 服務

REST servive

有了 REST 服務,就可以建立 TestCase,主要有兩種方式:

  • 自動生成,步驟如下:
    (1). 右鍵點擊一個 REST 服務,例如本例中的"BookStoreService", 選擇"Generate TestSuite"
    (2). 在彈出的對話框中,保持默認設置, 選擇"OK"
    (3). 輸入名稱 , 例如"BookStoreService TestSuite", 選擇"OK"即可。
  • 手工創建,步驟如下:
    (1). 在項目"BooksStoreTest"上點擊右鍵,選擇“New TestSuite”, 在對話框中輸入"BookStoreService TestSuite"
    (2). 在 BookStoreService TestSuite 上點擊右鍵, 選擇"New TestCase", 在對話框中輸入"BookList TestCase"
    (3). 然后在左邊的導航欄中展開 BookList TestCase, 在“Test Steps”上點右鍵,選擇 Add Step->Rest Test Request
    (4). 在彈出的對話框中選擇 GetBookListRequest_XML

一個完成的 TestCase 如 圖 4所示,用戶可以在其中加入 Assertion 對運行結果進行驗證,這也是自動化測試所必須的。

圖 4. REST TestCase

REST Test Case

使用變量

soapUI 支持使用自定義變量(Property)在 Project 中存儲和共享數據。Property 是一個命名的字符串可以被 Groovy Script,Property Transfer 或者 Property-Expansion 引用, 目前所有的變量均被處理為字符串。soapUI 允許在項目的各個層次中定義變量,常用的層次包括:Project,TestSuite,TestCase,Global 等。

1. 使用 Property 編輯器定義變量。
用戶可以使用 soapUI 自帶的 Property Editor 定義各個層次的變量。以 Project 變量為例,點擊 BookStoreTest,在 Properties 面板中添加自定義變量,如下圖所示:

圖 5. 使用 Property 編輯器定義項目變量

Project Property

2. 使用命令行指定變量。
修改 soapUI.bat 文件中的 Java 參數如下:

清單 x. 使用命令行指定變量
 set JAVA_OPTS=%JAVA_OPTS% -Xms128m -Xmx256m -Dsoapui.properties=properties.txt

其中,properties.txt 為指定的全局變量文件名字,可以通過添加如下代碼到全局變量文件來設置 project/testsuite/testcase 等層次的變量:

清單 x. 使用命令行指定變量
 soapui.properties.<shortened-name-of-object>=pathtopropertiesfile

<shortened-name-of-object> 為相應對象的名字。

3. 使用變量 
soapUI 使用如下語法引用項目中定義的變量:

清單 x. 使用命令行指定變量
 ${[scope]propertyName[#xpath-expression]}

其中,scope 可以為 #Project#,#TestSuite#,#TestCase# ,#Global#,#System#,#MockService#,#Env#,[TestStep name]#。

驗證結果

測試用例建好之后,需要向測試用例中添加 Assertions 以便驗證結果的正確性。soapUI 支持 Response SLA, Script Assertion, Contains, XQuery Match, Schema Compliance, XPath Match 以及 Not Contains 等多種斷言來對 response 進行判斷來保證對 Web 服務高質量的測試。本文以 XPath Match 和 Script Assertion 為例來對在線書店服務返回的 XML 和 JSON 格式的 response 進行判斷。

1. 使用 XPath Match 測試請求 GetBookListRequest_XML 返回的結果中,id 為 1234 的 book 的 price 為 29.0, response 參見 代碼清單 2

點擊 TestCase 的添加 Assertions 按鈕,如 圖 4所示。 在彈出的 Select Assertion 窗口中選擇 XPath Match 斷言,點擊 OK。配置 XPath 如下圖所示:

圖 6. 使用 XPATH 測試 XML 格式的書籍列表

XPath Match

在 XPath Expression 面板中書寫用於匹配 Response 的 XPath 表達式,Expected Result 面板中填寫期望的值。soapUI 將使用 XPath Expression 面板中填寫的 XPath 表達式與 Service 調用結果匹配, 將匹配結果與期望值比較,如果相同則測試通過,否則失敗。

2. 使用 Script Assertion 測試請求 GetBookListRequest_JSON 返回的結果,response 參見 代碼清單 1

Assertion 添加過程與 XPath Match 類似,在 Select Assertion 窗口中選擇 Script Assertion,並在之后彈出的 Script Assertion 窗口中書寫如下代碼:

清單 5. 使用 Script Assertion 測試 JSON 格式的書籍列表
 //assert the response header 
assert messageExchange.responseHeaders["Content-Type"]=="application/json;charset=UTF-8"; 
assert messageExchange.responseHeaders["Cache-Control"] == "no-cache"; 

 //assert the repsonse body 
 def booksRoot = net.sf.json.JSONSerializer.toJSON(messageExchange.responseContent); 
 def books = booksRoot.get("books"); 

 //assert book detail 
 assert books[0].get("book").get("id") == "1234"; 
 assert books[0].get("book").get("name") == "book1"; 
 assert books[0].get("book").get("price") == 29;

3. 使用 Property 測試請求 GetBookRequest_JSON 返回的結果, response 參見 代碼清單 3

在 Script Assertion 窗口中寫入如下代碼:

清單 6. 使用 Property 測試 JSON 格式的書籍詳情
 //get property 
 def expectedID = context.expand('${#Project#book.id}'); 
 def expectedName =  context.expand('${#Project#book.name}'); 

 //assert the response header 
 assert messageExchange.responseHeaders["Cache-Control"] == "no-cache"; 

 //assert the response body 
 def bookRoot = net.sf.json.JSONSerializer.toJSON(messageExchange.responseContent); 
 assert bookRoot.get("id") == expectedID; 
 assert bookRoot.get("name") == expectedName; 
 assert bookRoot.get("price") == 29.0;

上述使用 Groovy Script 對 Service 調用結果進行驗證,可用的 soapUI 對象包括 :messageExchange, context 以及 log。

  • messageExchange: 當前交互 request/response 的 MessageExchange,可以用來直接訪問 message content, HTTP Headers,Attachment 等對象。
  • context: 運行當前 TestCase 的 TestRunContext 對象,具體使用方式請參見 soapUI API 文檔。
  • log: 一個標准的 Log4j Logger 對象,可以用來輸出日志。

依照上述步驟定義好 TestCase 並添加適當的斷言之后,就可以對在線書店 REST 服務進行測試。雙擊 BookStoreSerive_TestSuite, 點擊 Run 按鈕來運行所有的 TestCase,結果如下圖所示:

圖 7. 運行測試用例

Run Test

 

性能測試

性能測試在 soapUI 中稱為 Load Test, 針對一個 soapUI 的 TestCase, 可以建立一個或多個 LoadTest, 這些 LoadTest 會自動的 把 TestCase 中的所有步驟都添加到其中, 在運行的時候,soapUI 會自動的使用多個線程來運行這些 TestStep,同時也會監控 它們的運行時間, 例如最短時間,最長時間,平均時間等等。這樣用戶能夠很直觀的看到 REST 服務的響應時間,從而對性能進行調優。

建立 LoadTest 非常簡單,只需要在“Load Tests”上點擊右鍵, 選擇"New LoadTest", 然后輸入名稱即可,下圖是一個針對 GetBookList 的 性能測試, 可以看到有兩個 TestStep : "GetBookList_xml" 和"GetBookList_json" , 100 個線程並發執行, 時間限制是 60 秒。 最后的結果是,最短時間 4 毫秒,最長時間 1204 毫秒,平均時間 20.54 毫秒。

圖 8. 性能測試

Load test

性能測試還支持斷言,用戶可以對一個 TestStep 或 TestCase 設置運行時間要求,例如平均時間大於 2 秒就認為失敗,點擊 圖 8 中中的 “LoadTest Assertions”就可以設置。 當然根據需要,用戶也可以編寫腳本來做一些准備工作,或者清除工作。 參見 圖 8 中的"Setup Script"和“TearDown Script”。

與 BuildForge 集成

測試可以有效的保證代碼的質量,但是僅僅手工的、在本機上運行的 REST 服務測試時遠遠不夠的。實際上把測試作為軟件構建的一部分,加入到持續集成中去是一個常見的敏捷開發實踐,通過頻繁的,自動化的測試, 可以更有效的發現缺陷,保證代碼質量。

IBM Rational BuildForge 是一個管理軟件構建和發布的平台 , 它提供了一個框架來自動化整個構建流程,不僅僅自動化單獨的任務,可以集成多種用戶現有的腳本和工具, 最大限度的保護用戶投資。作為一個框架,BuildForge 幾乎可以調用操作系統上的任何腳本。本文重點不在介紹 BuildForge, 假定讀者對 BuildForge 已經比較熟悉, 不熟悉的讀者可以查看參考資料中的相關文章。

對於 soapUI 來說,最簡單的一種集成方式就是提供命令行腳本讓 BuildForge 調用。在上文中 我們已經展示了通過 soapUI 的 GUI 運行 TestCase 的功能,那么 soapUI 可不可以通過命令行完成類似的功能呢? 答案是肯定的。

soapUI 提供了一個命令行工具 testrunner.bat 來運行一個項目中的 TestSuite, 可以在 <soap_ui_home>/bin 下找到它, 它的使用非常簡單,只需要設置下面的幾個常用參數即可:

  • -s 指定要運行的 TestSuite
  • -f 指定運行結果的輸出目錄
  • -j 生成 junit 風格的 report
  • -r 運行完成以后打印一個簡單的 summary

下面這行命令就是運行 bookstore.xml 這個 soapUI 項目中的 BookstoreTestSuite, 把結果輸出到 c:\temp\reports 中。
testrunner.bat -sBookstoreTestSuite -r -j C:\developerWorks\soapui\bookstore.xml -f c:\temp\reports

有了 testrunner,把 soapUI 的測試集成到 BuildForge 中就很簡單了,只需要在 BuildForge 的項目中添加一個步驟,參見下圖:

圖 9. BuildForge 中使用 testrunner

BuildForge and testrunner

 

總結

從上文可以看出,soapUI 是一款強大的 Web 服務測試工具 , 它提供了便利的 GUI 界面幫助用戶對 REST 服務進行快速的測試,使用簡單,學習成本很低。 它也提供了可編程能力例如變量,Groovy 腳本等, 以便讓用戶應對一些復雜的情況。 總而言之,有效的實際項目中使用 soapUI,可以極大的減輕工作量,提供工作效率。當然作為開源的工具, soapUI 仍然在不斷的發展完善過程中,本文所能介紹的也只是它的部分功能, 感興趣的讀者可以到 soapUI 網站上獲取更多資料。


免責聲明!

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



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