日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JUnit 5和Selenium –使用Selenium内置的`PageFactory`实现页面对象模式

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JUnit 5和Selenium –使用Selenium内置的`PageFactory`实现页面对象模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Selenium是一組支持瀏覽器自動化的工具和庫,主要用于Web應用程序測試。 Selenium的組件之一是Selenium WebDriver,它提供客戶端庫,JSON有線協議(與瀏覽器驅動程序進行通信的協議)和瀏覽器驅動程序。 Selenium WebDriver的主要優點之一是,它受所有主要編程語言的支持,并且可以在所有主要操作系統上運行。

在帶有Selenium WebDriver的JUnit 5的這一部分中,我將通過Selenium的內置PageFactory支持類來介紹Page Object模式的實現。 PageFactory提供了一種機制,用于初始化任何聲明使用@FindBy批注注釋的WebElement或List<WebElement>字段的Page對象。

關于本教程

您正在閱讀帶有Selenium WebDriver的JUnit 5的第二部分-教程 。

本教程中的所有文章:

  • 第1部分– 從頭開始設置項目–使用JUnit 5和Jupiter Selenium進行Gradle
  • 第2部分– 使用Selenium內置的PageFactory實現Page Object Pattern

接下來的是:

  • 第3部分–改進項目配置–并行執行測試,測試執行順序,參數化測試,AssertJ等

該教程的源代碼可以在Github上找到

介紹頁面對象模式

我們將在以下位置為基于JavaScript的Todo應用程序創建測試: http : //todomvc.com/examples/vanillajs 。 該應用程序被創建為單頁應用程序(SPA),并使用本地存儲作為任務存儲庫。 可能實現的方案包括添加和編輯待辦事項,刪除待辦事項,將單個或多個待辦事項標記為已完成。 該實現將使用Page Object模式完成。

頁面對象模式的目標是從實際測試中抽象出應用程序頁面和功能。 頁面對象模式提高了代碼在測試和固定裝置之間的可重用性,但也使代碼易于維護。

您可以在Martin Fowler的文章中了解有關此模式的更多信息: https : //martinfowler.com/bliki/PageObject.html

頁面API或頁面對象

我們將從將TodoMVC頁面建模為Page Object的項目開始。 該對象將表示將在測試中使用的頁面API。 可以使用接口對API本身進行建模。 如果查看以下界面的方法,則會注意到這些方法只是頁面上可用的用戶功能。 用戶可以創建待辦事項 ,用戶可以重命名待辦事項 ,也可以刪除待辦事項 :

public interface TodoMvc { void navigateTo(); void createTodo(String todoName); void createTodos(String... todoNames); int getTodosLeft(); boolean todoExists(String todoName); int getTodoCount(); List<String> getTodos(); void renameTodo(String todoName, String newTodoName); void removeTodo(String todoName); void completeTodo(String todoName); void completeAllTodos(); void showActive(); void showCompleted(); void clearCompleted(); }

上面的接口(顯然)隱藏了所有實現細節,但也沒有將任何Selenium WebDriver詳細信息公開給潛在的客戶端(在我們的情況下,客戶端=測試方法)。 實際上,它與Selenium WebDriver無關。 因此,從理論上講,我們可以針對不同的設備(例如移動本機應用程序,桌面應用程序和Web應用程序)使用此頁面的不同實現。

創建測試

定義了頁面API后,我們可以直接跳轉到創建測試方法。 在確認API可用于創建測試之后,我們將進行頁面實現。 這種設計技術使您可以專注于應用程序的實際使用,而不必太早進入實現細節。

創建了以下測試:

@ExtendWith (SeleniumExtension. class ) @DisplayName ( "Managing Todos" @DisplayName "Managing Todos" ) class TodoMvcTests { private TodoMvc todoMvc; private final String buyTheMilk = "Buy the milk" ; private final String cleanupTheRoom = "Clean up the room" ; private final String readTheBook = "Read the book" ; @BeforeEach void beforeEach(ChromeDriver driver) { this .todoMvc = null ; this .todoMvc.navigateTo(); } @Test @DisplayName ( "Creates Todo with given name" ) void createsTodo() { todoMvc.createTodo(buyTheMilk); assertAll( () -> assertEquals( 1 , todoMvc.getTodosLeft()), () -> assertTrue(todoMvc.todoExists(buyTheMilk)) ); } @Test @DisplayName ( "Creates Todos all with the same name" @DisplayName "Creates Todos all with the same name" ) void createsTodosWithSameName() { todoMvc.createTodos(buyTheMilk, buyTheMilk, buyTheMilk); assertEquals( 3 , todoMvc.getTodosLeft()); todoMvc.showActive(); assertEquals( 3 , todoMvc.getTodoCount()); } @Test @DisplayName ( "Edits inline double-clicked Todo" ) void editsTodo() { todoMvc.createTodos(buyTheMilk, cleanupTheRoom); todoMvc.renameTodo(buyTheMilk, readTheBook); assertAll( () -> assertFalse(todoMvc.todoExists(buyTheMilk)), () -> assertTrue(todoMvc.todoExists(readTheBook)), () -> assertTrue(todoMvc.todoExists(cleanupTheRoom)) ); } @Test @DisplayName ( "Removes selected Todo" ) void removesTodo() { todoMvc.createTodos(buyTheMilk, cleanupTheRoom, readTheBook); todoMvc.removeTodo(buyTheMilk); assertAll( () -> assertFalse(todoMvc.todoExists(buyTheMilk)), () -> assertTrue(todoMvc.todoExists(cleanupTheRoom)), () -> assertTrue(todoMvc.todoExists(readTheBook)) ); } @Test @DisplayName ( "Toggles selected Todo as completed" ) void togglesTodoCompleted() { todoMvc.createTodos(buyTheMilk, cleanupTheRoom, readTheBook); todoMvc.completeTodo(buyTheMilk); assertEquals( 2 , todoMvc.getTodosLeft()); todoMvc.showCompleted(); assertEquals( 1 , todoMvc.getTodoCount()); todoMvc.showActive(); assertEquals( 2 , todoMvc.getTodoCount()); } @Test @DisplayName ( "Toggles all Todos as completed" @DisplayName "Toggles all Todos as completed" ) void togglesAllTodosCompleted() { todoMvc.createTodos(buyTheMilk, cleanupTheRoom, readTheBook); todoMvc.completeAllTodos(); assertEquals( 0 , todoMvc.getTodosLeft()); todoMvc.showCompleted(); assertEquals( 3 , todoMvc.getTodoCount()); todoMvc.showActive(); assertEquals( 0 , todoMvc.getTodoCount()); } @Test @DisplayName ( "Clears all completed Todos" @DisplayName "Clears all completed Todos" ) void clearsCompletedTodos() { todoMvc.createTodos(buyTheMilk, cleanupTheRoom); todoMvc.completeAllTodos(); todoMvc.createTodo(readTheBook); todoMvc.clearCompleted(); assertEquals( 1 , todoMvc.getTodosLeft()); todoMvc.showCompleted(); assertEquals( 0 , todoMvc.getTodoCount()); todoMvc.showActive(); assertEquals( 1 , todoMvc.getTodoCount()); } }

更多:如果您不熟悉JUnit 5,則可以在我的博客上閱讀此介紹: https : //blog.codeleak.pl/2017/10/junit-5-basics.html 。 本文還有一個用波蘭語寫的較新版本: https : //blog.qalabs.pl/junit/junit5-pierwsze-kroki/ 。

在上面的測試類中,我們看到在每次測試之前,ChromeDriver均已初始化,并通過Selenium Jupiter擴展名(因此@ExtendWith(SeleniumExtension.class) )注入到設置方法( @BeforeEach )中。 驅動程序對象將用于初始化頁面對象。

頁面對象建模技術不同,并且很大程度上取決于您正在處理的項目的特征。 您可能要使用接口,但這不是必需的。 您可能需要考慮在較低的抽象級別上進行建模,在該級別上,API公開了更詳細的方法,例如setTodoInput(String value) , clickSubmitButton() 。

使用Selenium內置的PageFactory實現Page Object Pattern

到現在為止,我們已經有一個接口可以對TodoMVC頁面的行為進行建模,并且我們有使用API??的失敗測試。 下一步是實際實現頁面對象。 為此,我們將使用Selenium內置的PageFactory類及其實用程序。

PageFactory類簡化了Page Object模式的實現。 該類提供了一種機制,用于初始化任何聲明使用@FindBy批注注釋的WebElement或List<WebElement>字段的Page Object。 可以在org.openqa.selenium.support包中找到PageFactory和支持頁面對象模式實現的所有其他注釋。

下面的TodoMvcPage類實現了我們之前創建的接口。 它聲明了幾個用@FindBy注釋注釋的字段。 它還聲明一個構造函數,該構造函數采用工廠使用的WebDriver參數來初始化字段:

public class TodoMvcPage implements TodoMvc { private final WebDriver driver; private static final By byTodoEdit = By.cssSelector( "input.edit" ); private static final By byTodoRemove = By.cssSelector( "button.destroy" ); private static final By byTodoComplete = By.cssSelector( "input.toggle" ); @FindBy (className = "new-todo" ) private WebElement newTodoInput; @FindBy (css = ".todo-count > strong" ) private WebElement todoCount; @FindBy (css = ".todo-list li" ) private List<WebElement> todos; @FindBy (className = "toggle-all" ) private WebElement toggleAll; @FindBy (css = "a[href='#/active']" ) private WebElement showActive; @FindBy (css = "a[href='#/completed']" ) private WebElement showCompleted; @FindBy (className = "clear-completed" ) private WebElement clearCompleted; public TodoMvcPage(WebDriver driver) { this .driver = driver; } @Override public void navigateTo() { driver.get( " http://todomvc.com/examples/vanillajs " ); } public void createTodo(String todoName) { newTodoInput.sendKeys(todoName + Keys.ENTER); } public void createTodos(String... todoNames) { for (String todoName : todoNames) { createTodo(todoName); } } public int getTodosLeft() { return Integer.parseInt(todoCount.getText()); } public boolean todoExists(String todoName) { return getTodos().stream().anyMatch(todoName::equals); } public int getTodoCount() { return todos.size(); } public List<String> getTodos() { return todos .stream() .map(WebElement::getText) .collect(Collectors.toList()); } public void renameTodo(String todoName, String newTodoName) { WebElement todoToEdit = getTodoElementByName(todoName); doubleClick(todoToEdit); WebElement todoEditInput = find(byTodoEdit, todoToEdit); executeScript( "arguments[0].value = ''" , todoEditInput); todoEditInput.sendKeys(newTodoName + Keys.ENTER); } public void removeTodo(String todoName) { WebElement todoToRemove = getTodoElementByName(todoName); moveToElement(todoToRemove); click(byTodoRemove, todoToRemove); } public void completeTodo(String todoName) { WebElement todoToComplete = getTodoElementByName(todoName); click(byTodoComplete, todoToComplete); } public void completeAllTodos() { toggleAll.click(); } public void showActive() { showActive.click(); } public void showCompleted() { showCompleted.click(); } public void clearCompleted() { clearCompleted.click(); } private WebElement getTodoElementByName(String todoName) { return todos .stream() .filter(el -> todoName.equals(el.getText())) .findFirst() .orElseThrow(() -> new RuntimeException( "Todo with name " + todoName + " not found!" "Todo with name " " not found!" )); } private WebElement find(By by, SearchContext searchContext) { return searchContext.findElement(by); } private void click(By by, SearchContext searchContext) { WebElement element = searchContext.findElement(by); element.click(); } private void moveToElement(WebElement element) { new Actions(driver).moveToElement(element).perform(); } private void doubleClick(WebElement element) { new Actions(driver).doubleClick(element).perform(); } private void executeScript(String script, Object... arguments) { ((JavascriptExecutor) driver).executeScript(script, arguments); } }

@FindBy不是唯一用于在Page Object中查找元素的注釋。 還有@FindBys和@FindAll 。

@FindBys

@FindBys批注用于標記Page Object上的字段,以指示查找應使用一系列@FindBy標記。 在此示例中,Selenium將 id = "menu"的元素搜索class = "button"的元素:

@FindBys ({ @FindBy (id = "menu" ), @FindBy (className = "button" ) }) private WebElement element;

@FindAll

@FindAll批注用于標記Page Object上的字段,以指示查找應使用一系列@FindBy標記。 在此示例中,Selenium將搜索所有class = "button"的元素以及所有id = "menu"的元素。 不保證元素按文檔順序排列:

@FindAll ({ @FindBy (id = "menu" ), @FindBy (className = "button" ) }) private List<WebElement> webElements;

PageFactory提供了幾種靜態方法來初始化Page Objects。 在我們的測試中,在beforeEach()方法中,我們需要初始化TodoMvcPage對象:

@BeforeEach void beforeEach(ChromeDriver driver) { this .todoMvc = PageFactory.initElements(driver, TodoMvcPage. class ); this .todoMvc.navigateTo(); }

PageFactory使用反射初始化對象,然后初始化所有標有@FindBy批注的WebElement或List<WebElement>字段( @FindBy不進行任何查找,而是對字段進行代理)。 使用此方法要求Page Object具有接受WebDriver對象的單個參數構造函數。

定位元素

那么元素何時定位? 每次訪問該字段都會進行查找。 因此,例如,當我們執行代碼時: newTodoInput.sendKeys(todoName + Keys.ENTER); 在createTodo()方法中,實際執行的指令是: driver.findElement(By.className('new-todo')).sendKeys(todoName + Keys.ENTER) 。 我們可以預料,不是在對象初始化期間而是在第一個元素查找期間引發未找到元素的潛在異常。

Selenium使用代理模式來實現所描述的行為。

@CacheLookup

在某些情況下,每次訪問帶注釋的字段時都不需要查找元素。 在這種情況下,我們可以使用@CacheLookup批注。 在我們的示例中,輸入字段在頁面上沒有更改,因此可以緩存其查找:

@FindBy (className = "new-todo" ) @CacheLookup private WebElement newTodoInput;

運行測試

現在是執行測試的時候了。 可以從IDE或使用終端來完成:

./gradlew clean test --tests *TodoMvcTests

通過所有測試,構建成功:

> Task :test pl.codeleak.demos.selenium.todomvc.TodoMvcTests > editsTodo() PASSED pl.codeleak.demos.selenium.todomvc.TodoMvcTests > togglesTodoCompleted() PASSED pl.codeleak.demos.selenium.todomvc.TodoMvcTests > createsTodo() PASSED pl.codeleak.demos.selenium.todomvc.TodoMvcTests > removesTodo() PASSED pl.codeleak.demos.selenium.todomvc.TodoMvcTests > togglesAllTodosCompleted() PASSED pl.codeleak.demos.selenium.todomvc.TodoMvcTests > createsTodosWithSameName() PASSED pl.codeleak.demos.selenium.todomvc.TodoMvcTests > clearsCompletedTodos() PASSED BUILD SUCCESSFUL in 27s 3 actionable tasks: 3 executed

下一步

在本教程的下一部分中,您將學習如何改善項目配置。 您將學習并行執行測試,測試執行順序,參數化測試,AssertJ等。

翻譯自: https://www.javacodegeeks.com/2019/10/using-pagefactory-implement-page-object-pattern.html

總結

以上是生活随笔為你收集整理的JUnit 5和Selenium –使用Selenium内置的`PageFactory`实现页面对象模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。