IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 基于Typescript 的 PageObject 自动化测试模型 -> 正文阅读

[开发测试]基于Typescript 的 PageObject 自动化测试模型

项目结构介绍

在编写自动化测试程序时,就需要操作Web页面上的元素。然而Web页面上的元素的定位路径或定位方式又具有易变性,所以直接式编程的方式是及其脆弱的。

page object 模型简介

page对象的一个基本法则是:凡是人能做的事,page对象通过软件客户端都能做到。因此,它应当提供一个易于编程的接口,并隐藏窗口中的底层部件。当访问一个文本框时,应该通过一个访问方法(Accessor Methos)实现字符串的获取与返回,复选框应当使用布尔值,按钮应当被表示行为导向的方法名。page对象应当把GUI控件上所有查询和操作数据进行封装为方法。page对象一个好的经验法则时,即使改变具体的元素,page对象的接口也不应发生改变。

Page Object 原理

Page Object 原理

Page Object 是一种设计模式,在自动画测试开发中遵循这种设计模式来编写代码。
Page Object 应遵循一下原则进行开发:

  • Page Object 应该以用于使用
  • 有清晰的结构,如 PageObject 对应页面对象,PageModules 对应页面的内容
  • 只写测试内容,不写基础内容
  • 在可能的情况下防止样板代码
  • 不需要自己管理浏览器
  • 在运行时选择浏览器,而不是类级别。
  • 不需要直接接触Selenium。

介绍目录结构

在这里插入图片描述

Page Object 项目结构图

目录/文件说明

  • modeling/:GUI控件上所有查询和操作数据进行封装为方法
  • page_object/:用于存放page层的封装。
  • test_dir/:测试用例目录。
  • test_iperation/:测试用例操作方法封装。
  • test_report/:测试报告目录。
  • conftest.ts:测试配置文件。
  • run_tests.ts:测试运行文件。

命名与设计规范

  1. 对于page层的封装存放于page_object/目录,命名规范为“xxx_page.ts”.
  2. 对于测试用例的编写存放于test_dir/目录,命名规范为“test_xxx.ts”
  3. 每一个功能对应一个测试类,并以“Test” 开头, 如“TestLogin”、“TestSearch”等。
  4. 在一个测试类下编写功能点的所有测试用例,如“testLoginUserNull”、”testLoginPawdNull“、”testLoginSuccess“等。

文件代码

modeling 目录

./src/modeling/loging.ts



// 输入日志配置文件,用于输入定位元素日志
// 后续增加日志输入流方式

// 临时设置日志输出到终端
export function debug(msg: string) {
    console.log(msg)
}

export function info(msg: string) {
    console.log(msg)
}

export function error(msg: string) {
    console.log(msg)
}

export function warn(msg: string) {
    console.log(msg)
}

export function fatal(msg: string) {
    console.log(msg)
}

export function print(msg: string) {
    console.log(msg)
}

./src/modeling/page_objects.ts

import { Builder, By, Key, Locator, logging, ThenableWebDriver, until, WebDriver, WebElement, WebElementPromise} from "selenium-webdriver";
import * as logger from "./logging";

export abstract class PageObject {
    private url: string;
    // Page Object pattern.
    protected setUrl(url: string) {
        this.url = url;
    }

    public async get(uri: string): Promise<void> {
        // :param uri:  URI to GET, based off of the root_uri attribute.
        await this.driver.get(this.url) 
    }

    public constructor(protected driver: ThenableWebDriver|WebDriver, url:string="") {
        // :param driver: `selenium.webdriver.WebDriver` Selenium webdriver instance
        // :param url: `str`
        // Root URI to base any calls to the ``PageObject.get`` method. If not defined
        // in the constructor it will try and look it from the webdriver object.
        this.url = url;
        this.driver = driver;
    }
}


export class PageElement {
    driver: ThenableWebDriver|WebDriver;
    locator: Locator;
    timeOut: number;
    describe: string;
    index: number;


    constructor(driver:ThenableWebDriver|WebDriver, locator: Locator, timeOut: number=5000, describe="undefined", index=0) {
        this.driver = driver;
        this.locator = locator;
        this.timeOut = timeOut;
        this.describe = describe;
        this.index = index;
    }

    public async __findElement(driver=this.driver, locator:Locator) {
        try {
            await driver.wait(until.elementLocated(locator), this.timeOut);
            // 此处可以设置为 工程日志
            let errorMsg: string = `? Find element:: ${locator}`;
            logger.info(errorMsg);
        } catch (error) {
            let errorMsg: string = `? Find 0 elements through: ${locator}, describe:${this.describe}`;
            let end_date: Date = new Date();  
            console.log("end_date = " + end_date);  
            logger.error(errorMsg)
            throw Error(errorMsg);      // 抛出异常
        }
        // return await driver.wait(until.elementLocated(locator), this.timeOut);
        return await driver.findElement(locator)
    }

    public async getElement(driver=this.driver, locator:Locator): Promise<WebElement> {
        let elem = await this.__findElement(driver, locator);
        if(false) {
            // 内部编写被找到元素的显示方式/提示方式
            // 待后续扩展
        }
        return elem;

    }


    public async clear(){
        // Clears the text if it's a text entry element.
        let elem = await this.getElement(this.driver, this.locator);
        logger.info(`clear element: ${this.describe}`);
        elem.clear()
    }

    public async sendKeys(value: string) {
        // Simulates typing into the element.
        let elem = await this.getElement(this.driver, this.locator);
        logger.info(`🖋 input element: ${this.describe}`);
        (await elem).sendKeys(value)
    }

    public async click() {
        // Clicks the element.
        let elem = await this.getElement(this.driver, this.locator);
        logger.info(`🖱 click element: ${this.describe}`);
        (await elem).click()
    }

    public async submit() {
        // Submits a form.
        let elem = await this.getElement(this.driver, this.locator);
        logger.info(`submit element: ${this.describe}`);
        (await elem).submit()
    }

    public async getTagName() {
        // This element's ``tagName`` property.
        let elem = await this.getElement(this.driver, this.locator);
        (await elem).getTagName()
    }

    public async  getText(){
        // Clears the text if it's a text entry element.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.getText()
    }
        
    public async getSize(){
        // The size of the element.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.getSize()
    }

    public async getCssValue(property_name: string){
        // The value of a CSS property.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.getCssValue(property_name)
    }


    public async getAttribute(name: string){
        // The value of a CSS property.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.getAttribute(name)
    }

    public async isDisplayed(){
        // Whether the element is visible to a user.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.isDisplayed()
    }

    public async findElement(locator: Locator){
        // Find an element given a By strategy and locator。
        let elem = await this.getElement(this.driver, this.locator);
        return elem.findElement(locator)
    }

    public async findElements(locator: Locator){
        // Find elements given a By strategy and locator.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.findElements(locator)
    }

    public async getId(){
        // A promise that resolves to the server-assigned opaque ID assigned to this element.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.getId()
    }

    public async getLocation(){
        // Schedules a command to compute the location of this element in page space.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.getLocation()
    }

    public async getRect(){
        // Returns an object describing an element's location, in pixels relative to the document element, and the element's size in pixels.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.getRect()
    }

    public async isEnabled(){
        // Schedules a command to query whether the DOM element represented by this  instance is enabled, as dicted by the {@code disabled} attribute.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.isEnabled()
    }

    public async isSelected(){
        // Schedules a command to query whether this element is selected.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.isSelected()
    }

    public async selectByValue(value: string){
        // Select all options that display text matching the argument. That is, when given "Bar" this would select an option like:
        let elem = await this.getElement(this.driver, this.locator);
        await elem.click();
        await elem.findElement(By.css(`option[value="${value}"]`)).click;
    }
    
    public async selectByIndex(index: number){
        // Select all options that display text matching the argument. That is, when given "Bar" this would select an option like:
        let elem = await this.getElement(this.driver, this.locator);
        await elem.click();
        await elem.findElement(By.css(`option:nth-child(${index})`)).click;
    }
    
    public async selectByText(text: string){
        // Select all options that display text matching the argument. That is, when given "Bar" this would select an option like:
        let elem = await this.getElement(this.driver, this.locator);
        await elem.click();
        await elem.findElement(By.css(`option:textContent="${text}")`)).click;
    }

    public async takeScreenshot(){
        // Take a screenshot of the visible region encompassed by this element's bounding rectangle.
        let elem = await this.getElement(this.driver, this.locator);
        return elem.takeScreenshot()
    }

    public async enter(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.END)
    }

    public async SelectAll(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.CONTROL, "a")
    }

    public async cut(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.CONTROL, "x")
    }

    public async copy(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.CONTROL, "c")
    }

    public async paste(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.CONTROL, "v")
    }

    public async backspace(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.BACK_SPACE)
    }

    public async delete(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.DELETE)
    }

    public async tab(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.TAB)
    }

    public async space(){
        let elem = await this.getElement(this.driver, this.locator);
        return elem.sendKeys(Key.SPACE)
    }
}

export class PageElements {
    driver: ThenableWebDriver|WebDriver;
    locator: Locator;
    timeOut: number;
    describe: string;
    index: number;


    constructor(driver:ThenableWebDriver|WebDriver, locator: Locator, timeOut: number=5000, describe="undefined", index=0) {
        this.driver = driver;
        this.locator = locator;
        this.timeOut = timeOut;
        this.describe = describe;
        this.index = index;
    }

    public async find(){
        let elems: WebElement[] = []
        try {
            elems = await this.driver.findElements( this.locator);
        } catch (error) {
            elems = [];
        }
        logger.info(`? Find ${elems.length} elements through: ${this.locator}, describe:${this.describe}`);
        return elems;
    }

}

page_object 目录

./src/baidu_oage.ts

import { By, ThenableWebDriver, WebDriver } from "selenium-webdriver";
import { PageElement, PageObject } from "../modeling/page_objects";

export class BaiduPage extends PageObject{
    driver: ThenableWebDriver|WebDriver
    constructor(driver: ThenableWebDriver|WebDriver) {
        super(driver);
        this.driver = driver
    }

    inp = new PageElement(this.driver, By.css('#kw'));          // 百度输入框定位器
    btn = new PageElement(this.driver, By.css('#su'), 3000, "定位百度一下按钮");          // 百度一下按钮定位器

}

./src/draw_page.ts

import { By, ThenableWebDriver, WebDriver } from "selenium-webdriver";
import { PageElement, PageObject } from "../modeling/page_objects";

export class DrawPage extends PageObject{
    driver: ThenableWebDriver|WebDriver
    constructor(driver: ThenableWebDriver|WebDriver) {
        super(driver);
        this.driver = driver
    }

    colorList = new PageElement(this.driver, By.id('color-list'));          // 颜色值列表
}

test_dir

./src/test_dir/singeinstance.ts

import { WebDriver, Builder } from "selenium-webdriver";

export class SingleInstance{
    private static instance: WebDriver;

    public static create_driver() {
        if(! this.instance) {
            this.instance = new Builder().forBrowser("chrome").build()  //创建一个浏览器实例
        }  // 如果instance为空就创建
        return this.instance
    }
}

./src/test_dir/excutejs.ts

import { Builder, By, Locator, logging, ThenableWebDriver, until, WebDriver, WebElement, WebElementPromise} from "selenium-webdriver";
import { BaiduPage } from "../page_object/baidu_page";
import { SingleInstance } from "./singleinstance";




// 延时函数 不建议使用
// 适用于调试使用
var sleep = function(time: number) {
    var timeOut = new Date().getTime() + time;
    while(new Date().getTime() <= timeOut) {};
};



async function main() {
    const driver = SingleInstance.create_driver();
    await driver.get("https://www.baidu.com");

    const page = new BaiduPage(driver);
    await page.inp.sendKeys("helloworld")
    // sleep(1000)
    await page.inp.clear()
    // sleep(1000)
    await page.inp.sendKeys("成功")

    let satrar_date: Date = new Date();  
    console.log("satrar_date = " + satrar_date); 

    await page.btn.click()
    await driver.wait(until.elementLocated(By.xpath('//a[@class="toindex"]')), 10000).click;
    const res = await driver.findElement(By.xpath('//a[@class="toindex"]')).getText()
    console.log("--------------------------------------------")
    console.log(By.xpath('//a[@class="toindex"]').using)
    console.log(By.xpath('//a[@class="toindex"]').value)
    console.log(res)
    console.log("--------------------------------------------")

    // driver.quit()

    
    // const driver = SingleInstance.create_driver();
    // await driver.get("https://draw.yunser.com/");
    // await driver.manage().window().maximize();

    // const page = new DrawPage(driver);
    // let elem = await page.colorList;
    // let attr:string = await elem.getAttribute("id")

    // console.log("--------------------------------------------")
    // console.log(attr)
    // let ele = await elem.findElement(By.css(`li:nth-child(2)`))
    // let dataColor = await ele.getAttribute("data-color")
    // console.log(dataColor)
    // console.log("--------------------------------------------")


}

main()

test_operation 和 test_report目录目前为空

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-10-13 11:43:43  更:2021-10-13 11:44:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 2:55:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码