Selenium WebDriver—如何測試REST API

  • 2019 年 10 月 7 日
  • 筆記

前言:關於如何使用selenium webdriver測試REST api的問題,你可以在StackOverflow.com上看到很多相關的問題。不熟悉自動化測試的新人有時不理解Selenium僅僅基於WebUI做自動化測試。但是,如果你想使用Selenium為UI測試執行一些數據設置/數據清理,那麼可以通過一些額外的庫來實現這一點;這就是我們將在本文中看到內容。

Web UI測試存在的問題:

  • 慢(這是因為你的瀏覽器首先向伺服器發送一個請求以獲取某些資訊,一旦獲得所需數據,可能需要一些時間來處理數據,並通過下載的圖片和應用樣式使其顯示在表格中/或者以適配的格式顯示,所以你必須等待整個過程完成之後才能與應用程式進行交互);
  • 費時;
  • 對於測試不同的瀏覽器,可能必須重複相同的測試集;
  • 瀏覽器是獨立於selenium腳本的進程。所以同步總是一個問題;
  • UI測試有很多依賴項,比如Browsers/Versions/Grid/Driver等等。

因此,這並不意味著我們應該總是做API級別的測試並發布產品;我們應該嘗試儘可能的進行API級別測試。我們可以只為UI測試提供較小覆蓋率。

REST API測試:與Selenium WebDriver UI測試相比,REST API測試並不難,大多數api都是GET / POST / PUT / PATCH / DELETE請求之一:

  • GET 用於從後端獲取資訊以顯示在UI中;
  • POST 用於在後端添加新資訊;
  • PUT用於更新/替換任何現有資訊;
    • PATCH 用於部分更新;
  • DELETE 用於從後端刪除資訊。

如果你的目的是對REST api進行詳盡的測試,我建議看看JMeter。你可以查看下面關於使用JMeter進行REST API測試的文章。

  • JMeter – 如何測試REST API / 微服務[2]
  • JMeter – REST API Testing – 一個完整的數據驅動方法[3]
  • 微服務 – 契約測試[4]

假設你使用testNG/Junit這樣的框架,並使用Selenium進行應用程式UI測試 –而現在希望在相同的框架中也包含API測試 –可能需要快速設置數據或斷言等,那麼接下來就讓我們看看如何在本文中完成。

依賴包

在maven文件中添加如下依賴:

<dependency>      <groupId>com.mashape.unirest</groupId>      <artifactId>unirest-java</artifactId>      <version>1.4.9</version>  </dependency>  <dependency>      <groupId>org.jtwig</groupId>      <artifactId>jtwig-core</artifactId>      <version>5.87.0.RELEASE</version>  </dependency>
  • Unirest是一個簡單的輕量級流暢式HTTP請求庫
  • JTwig是一個非常簡單的模板引擎

程式示例:

我將考慮這個應用程式[5]進行測試。

注意:本文並沒有去下載該開源項目部署到本地,而是使用了已經部署在GitHub上的該項目作為學習使用,Live Demo: https://restool-sample-app.herokuapp.com/,倘若你有興趣部署可以嘗試下自己部署

使用Rest API列出所有可用的聯繫人,添加/編輯/刪除聯繫人;它還使用Angular構建了比較友好的UI介面;你可以克隆並部署到你的本地運行。一旦上述應用程式部署成功並啟動,就可以使用API GET請求獲取聯繫人列表,顯示在UI介面上。

1-獲取聯繫人

當您訪問應用程式的主頁時,它會列出所有可用的聯繫人。

如果監視Chrome-network中的Network,可以看到發送了一些API GET請求來獲取聯繫人列表。

  • 如果你不確定在哪裡檢查,在Chrome頁面按下F12,Chrome開發工具將會出現。
  • 檢查API url的header部分

F12 開發者工具

本地部署的地址  https://localhost:4200/api/contacts?q=  而本文例子使用如下Live Demo鏈接:  https://restool-sample-app.herokuapp.com/

你可以看到以下格式的JSON Response:

[      {          "id": "xiyydaS9CLqV",          "thumbnail": "https://www.hbo.com……",          "name": "Tyrion Lannister",          "realName": "Peter Dinklage",          "location": "Winterfell",          "isAlive": true      }  ]

你可以通過應用程式添加聯繫人,修改聯繫人,刪除聯繫人

2- GET Request:

一旦應用程式啟動,可以使用API GET請求獲取聯繫人列表,以便在應用程式中顯示數據。可以使用Unirest發出上面說到的GET請求,如下所示:

String searchQueryApi = "https://restool-sample-app.herokuapp.com/api/character?search=";    JsonNode body = Unirest.get(searchQueryApi)                          .asJson()                          .getBody();  System.out.println(body);         // 列印完整的json響應資訊  System.out.println(body.getArray().length());  // 列印item編號

其請求如下圖所示:

也可以在測試框架中進行簡單的斷言。例如下面的示例程式碼確認API響應中的所有數據是否都顯示在UI中:

driver = new ChromeDriver();  driver.manage().window().maximize();  driver.get("https://restool-sample-app.herokuapp.com/");  List<WebElement> contacts = driver.findElements(By.cssSelector("tbody > tr"));  Assert.assertEquals(contacts.size(), body.getArray().length(), "The contacts not equals with Body length");

3- POST Request:

每當我們試圖添加新的聯繫人時,就會發送POST請求並攜帶如下格式JSON作為Body:

{  	"thumbnail": "https://www.hbo.com……",  	"name": "Test Name",  	"realName": "Test Real Name",  	"location": "Test location",  	"isAlive": false  }

如果你的目標是自己發送請求,那麼您可能不希望在JSON文件中硬編碼任何值。這就是我們使用JTwig模板引擎的地方。首先,我在模板下面創建。

{    "thumbnail": "{{URL}}",    "name": "{{name}}",    "realName": "{{realName}}",    "location": "{{location}}",    "isAlive": true  }

我將上面的JSON保存在一個名為「contact.json」的文件中。現在我可以讀取模板並在運行時替換這些值,如下所示:

JtwigTemplate template = JtwigTemplate.classpathTemplate("contact.json");  JtwigModel model = JtwigModel.newModel()  	.with("URL", "http://n.sinaimg.cn/ent/transform/20160502/n4qY-fxrunru8640821.png")  	.with("name", "TestName")  	.with("realName", "TestRailName")  	.with("location", "Winterfell");  template.render(model);//用上述的值替換模板表達式中的值

接下來可以發送POST請求創建新的聯繫人了(發送POST請求之後,在這裡還可以通過UI介面進行檢查聯繫人是否成功顯示在UI介面,此處不做詳細Demo)

String postApi = "https://restool-sample-app.herokuapp.com/api/character";  Unirest.post(postApi)  	.header("accept", "application/json")  	.header("Content-Type", "application/json")  	.body(template.render(model))  	.asJson();

使用上面這個方法,我們可以在應用程式中快速的添加聯繫人。

假設頁面最多只能顯示50個聯繫人,你需要點擊翻頁按鈕查看更多聯繫人,但是在本地/QA環境中,當你啟動一個新的應用程式時,可能沒有足夠的聯繫人來測試該顯示功能;如果頁面對象公開了一個方法來添加聯繫人,則需要調用50多次,通過UI介面添加聯繫人可能非常耗時,由於同步問題,它可能隨時會失敗,並且還需要處理:比如當用例重試失敗或者退出導致測試失敗等情況。

但是使用Api,您可以輕鬆地修改頁面對象,如下所示,現在你可以用它來建立數據等等。它應該比UI方法快得多,而且更不容易出錯。

class ContactsPage{      //all find bys      //methods for interacting with web elements      public void addContacts(int numberOfContacts){          String postApi = "https://restool-sample-app.herokuapp.com/api/character";          for(int i = 0; i<numberOfContacts; i++){              Unirest.post(postApi)                      .header("accept", "application/json")                      .header("Content-Type", "application/json")                      .body(template.render(model))                      .asJson();          }        }    }

Unirest可以很容易地在page對象中使用,如上面的示例所示。

4- 編輯請求

要編輯聯繫人,我們需要發送如下所示的PUT請求。

String editApi = "https://restool-sample-app.herokuapp.com/api/character/{contact_id}";    JtwigModel model = JtwigModel.newModel()  		.with("name", "Snow")          .with("location", "Winterfell");    Unirest.put(editApi)          .routeParam("contact_id", "T2S6kHv4cS1A")          .header("accept", "application/json")          .header("Content-Type", "application/json")          .body(template.render(model))          .asJson();

更新了Name:

5- 刪除請求

刪除就這就更簡單了。

String editApi = "https://restool-sample-app.herokuapp.com/api/character/{contact_id}";    Unirest.delete(editApi)          .routeParam("contact_id", "T2S6kHv4cS1A")          .asJson();

我們可以使用這個API來清理測試中新建的數據,這樣就保持測試之後的數據清潔,不會過多的新建無用甚至垃圾數據。

public class ContactsPageTest{      private String editApi = "https://localhost:4200/api/contacts/{contact_id}";        @Test      public void someUItest1(){          //      }        @Test      public void someUItest2(){          //      }        @AfterTest      public void teardown(){          for(String contactid: listOfContacts){              Unirest.delete(editApi)              .routeParam("contact_id", contactid)              .asJson();          }      }    }

總結:通過在現有的測試框架/頁面對象中使用Unirest,可以和REST api進行交互,還可以使用這些api在應用程式中進行快速設置數據,以便進行快速功能驗證;正如上面的示例中所提到的,只要可能,就盡量使用api進行測試。