JUnit 5和Selenium基础(二)

使用Selenium内置的PageFactory实现页面对象模式

在这一部分中,将通过Selenium的内置PageFactory支持类来介绍Page Object模式的实现。PageFactory提供一种机制来初始化任何声明WebElementList<WebElement>带有@FindBy注释的字段的Page Object

由于不可描述的原因,我已经将测试网页打包,需要的请留意文末信息。

介绍页面对象模式

页面对象模式的目标是从实际测试中抽象出应用程序页面和功能。页面对象模式提高了代码在测试和固定装置之间的可重用性,但也使代码易于维护。

页面API或页面对象

我们将从将TodoMVC页面建模为Page Object 的项目开始。该对象将表示将在测试中使用的页面API。可以使用接口对API本身进行建模。如果查看以下界面的方法,则会注意到这些方法只是页面上可用的用户功能。用户可以创建待办事项,用户可以重命名待办事项,也可以删除待办事项:

publicinterface 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无关。因此,从理论上讲,我们可以针对不同的设备(例如移动本机应用程序,桌面应用程序和Web应用程序)使用此页面的不同实现。

创建测试

定义了页面API后,可以直接跳转到创建测试方法。在确认API可用于创建测试之后,再进行页面实现。这种设计模式使测试人员可以专注于应用程序的实际使用,而不必太早掉进细节的坑里。

创建了以下测试:

@ExtendWith(SeleniumExtension.class)
@DisplayName("Managing Todos")
class TodoMvcTests {
 
    private TodoMvc todoMvc;
 
    privatefinal String buyTheMilk = "Buy the milk";
    privatefinal String cleanupTheRoom = "Clean up the room";
    privatefinal 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")
    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")
    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")
    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());
    }
}

在上述测试类中,我们看到在每次测试之前,ChromeDriver均已@BeforeEach通过Selenium Jupiter扩展名(@ExtendWith(SeleniumExtension.class))初始化并注入到设置方法中。驱动程序对象将用于初始化页面对象。

页面对象模式很大程度上取决于项目的特征。你可能要经常使用接口,但这不是必需的。你可能要考虑在较低的抽象水平,其中API是暴露的更详细的方法,例如setTodoInput(String value)clickSubmitButton()

使用Selenium内置的PageFactory实现Page Object Pattern

我们已经有一个接口可以对TodoMVC页面的行为进行建模,并且我们有使用API的失败测试。下一步是实际实现页面对象。为此,我们将使用Selenium内置PageFactory类及其实用程序。

PageFactory类简化了页面对象模式的实现。该类提供了一种机制来初始化任何声明WebElementList<WebElement>带有@FindBy注释的字段的Page ObjectPageFactory中提供了支持Page Object模式实现的和其他注释。

下面的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("***");
    }
 
    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!"));
    }
 
    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标签。在这个例子中,硒将搜索元件与class = "button"是内与元件id = "menu":

@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对象

PageFactory提供了几种静态方法来初始化Page Objects。在我们的测试中,在beforeEach()方法中,我们需要初始化TodoMvcPage对象:

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

PageFactory使用反射初始化对象,然后将其初始化所有WebElementList<WebElement>标有字段@FindBy注释。使用此方法要求Page Object具有单个参数构造函数接受WebDriver对象。

定位元素

那么元素何时定位?每次访问该字段都会进行查找。例如,当我们执行代码:new TodoInput.sendKeys(todoName + Keys.ENTER);in 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
 
demos.selenium.todomvc.TodoMvcTests > editsTodo() PASSED
 
demos.selenium.todomvc.TodoMvcTests > togglesTodoCompleted() PASSED
 
demos.selenium.todomvc.TodoMvcTests > createsTodo() PASSED
 
demos.selenium.todomvc.TodoMvcTests > removesTodo() PASSED
 
demos.selenium.todomvc.TodoMvcTests > togglesAllTodosCompleted() PASSED
 
demos.selenium.todomvc.TodoMvcTests > createsTodosWithSameName() PASSED
 
demos.selenium.todomvc.TodoMvcTests > clearsCompletedTodos() PASSED
 
BUILD SUCCESSFUL in 27s
3 actionable tasks: 3 executed

俺叫小枫,一个成天想着一夜暴富的测试员

(1140267353)一起成长一起加油的伙伴群!软件测试,与你同行!
群内可领取最新软件测试大厂面试资料和Python自动化、接口、框架搭建学习资料!

点赞关注不迷路!!!【三连ღ】,有问题也可私聊哟~(*╹▽╹*)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java是一种高级编程语言,应用广泛,可以用于开发各种类型的程序。JUnit5是Java开发中非常流行的测试框架,可以对代码单元进行测试,确保程序的正确性。Maven是Java开发者常用的构建工具,帮助开发者管理项目依赖、构建和管理项目。 Jenkins是一个持续集成工具,可以帮助开发者自动化地构建、测试和部署代码,并且支持多种编程语言。Selenium是一个广泛使用的自动化测试工具,可以模拟用户行为,测试Web应用程序并进行UI测试。通常与Java和JUnit5一起使用,可以大大简化测试过程,提高测试效率和可靠性。综上所述,Java、JUnit5、Maven、Jenkins和Selenium是Java开发者常用的一些重要工具,它们结合使用可以提高开发效率和代码质量,同时也有助于保障Web应用程序的可靠性和稳定性。 ### 回答2: Java是一种计算机编程语言,广泛用于开发企业级应用程序和移动应用程序。它是一种跨平台语言,可以在各种操作系统上运行。其面向对象的语言特性使得开发人员可以更轻松地构建可维护、可扩展的应用。 JUnit 5是一个开源的Java测试框架,可用于编写单元测试,集成测试和功能测试。它提供了丰富的测试注解和断言,能够优化测试开发过程。JUnit 5支持Java 8及以上版本,并且具有更好的可扩展性和灵活性。 Maven是一个Java项目管理和构建工具,可以自动下载项目依赖库,并负责编译,测试,打包和发布应用程序。它可以管理多个项目和模块,并且具有统一的目录结构和构建流程,提高了项目的可维护性和开发效率。 Jenkins是一个自动化构建和持续集成工具,可以监控版本控制系统中的代码变化,自动触发构建和测试,并且能够将构建结果进行分析和报告。Jenkins支持插件扩展,可以轻松地与其他工具集成,提高了持续集成的灵活性和可靠性。 Selenium是一个自动化Web应用测试工具,可以模拟用户交互,进行功能测试,回归测试和性能测试。它支持多种编程语言,包括Java和JUnit 5,并且能够在不同的浏览器和操作系统上运行,是开发Web应用的重要工具。 ### 回答3: Java是一种广泛使用的编程语言,它具有面向对象的特点,可以在不同的平台上运行。Junit5是Java中使用的测试框架,可以用来编写测试用例、测试断言和执行测试。Maven是Java的一个构建工具,可以管理项目中的依赖项、编译、测试、打包和部署等过程。Jenkins是一个流行的持续集成工具,可以对Java项目进行持续集成和自动化测试。Selenium是一种自动化测试工具,可以用来模拟浏览器行为,自动化测试Web应用程序。 在Java的开发过程中,常常需要进行测试,以保证程序的质量和正确性。Junit5是Java中使用的一个成熟的测试框架,它可以用来编写测试用例、测试断言和执行测试等操作。Maven可以管理项目中的依赖项、编译、测试、打包和部署等过程,可以大大简化项目的构建和管理。Jenkins可以集成Junit5Selenium等测试工具,对Java项目进行持续集成和自动化测试,大大提高开发效率和代码质量。 Selenium是一种自动化测试工具,可以用来模拟浏览器行为,对Web应用程序进行自动化测试。它可以模拟用户在浏览器中的操作,比如单击、输入、滚动、切换窗口等,通过代码自动化地执行这些操作,并对应用程序的响应结果进行断言和验证。因此,Selenium非常适合用于测试Web应用程序。结合Junit5和Jenkins等工具,可以实现自动化的测试流程,提高测试效率和准确度。 综上所述,Java、Junit5、Maven、Jenkins和Selenium是Java开发中常用的一些工具和框架,它们可以提高开发效率,保证程序的质量和稳定性,是Java开发者必备的知识点和技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值