Selenium+Junit5 WebUI自动化

PO模式:

以页面为单位独立建模,隐藏实现的细节,本质是面向接口编程。

封装基础类,driver调用、元素操作方法等的封装

创建页面返回类,用于返回各个页面,所以可不设方法

创建相应page类,用于元素定位、封装业务操作方法

创建测试类

关于奶茶工作台的WebUI自动化的实现

需求须知:奶茶点单微信小程序的工作台。主要模块:登陆、修改密码、订单管理、配料管理、财务管理、退出登录

框架选取:Junit5+Selenium

设计用例组织结构:page【页面封装】+driver【对Web驱动】+testcase【调用page完成业务流程并做断言】+data【数据驱动】+utils【其他工具封装】

用例组织结构
page+driver
BasePage:封装driver层的各种方法,Page层的父类
App:继承BasePage
定义各个界面,并返回
定义公共方法,比如:获取coolie信息
LoginPage
OrderPage
IngredientPage
AccountLogPage
LoginPage:继承BasePage
正常流登陆/异常流登陆/验证码校验实现
OrderPage:继承BasePage
查询/删除功能
IngredientPage:继承BasePage
增删改查
AccountLogPage:继承BasePage
删除/查询功能
data:csvFileSource驱动
testcase
业务流程处理:正常/异常
断言assertThat
测试数据清理

测试分析:

  • 登陆–验证码处理:(1)去掉验证码,线上不安全;(2)程序开“后门”,设置万能验证码,测试人员获取即可。–采用
  • Cookie获取:
	driver.manage().getCookies();
  • 数据驱动:
    @ParameterizedTest
    @CsvFileSource(resources = "1.csv")
    public void addIngredient(String name,double price){
       //todo
    }
  • 测试步骤驱动:
	public static App app;
    public static IngredientPage ingredientPage;

    @BeforeAll
    public static void beforeAll(){
        app = new App();
        ingredientPage= new IngredientPage ();
        app.LoginWithCookies();
    }
    @AfterAll
    public static void quit(){
        app.quit();
    }
	@RunWith(Suite.class)
    @Suite.SuiteClasses({
            testcase.TestIngredient.class
    })

常用Selenium方法:

定义WebDriver对象,且结束测试时需要关闭
	public static WebDriver driver;

	public void quit(){
        driver.quit();
    }
请求页面
driver.get("https://***/");
登陆完成后,获取cookies
public Cookie getCookie(){
        //todo:完成登陆操作
        return driver.manage().getCookieNamed("wwrtx.sid");
    }
在相应Page层中添加cookies
driver.manage().addCookie(new Cookie("cookie","***"));
定位元素节点
public WebElement findElement(By by){
        return driver.findElement(by);
    }
    
public List<WebElement> findElements(By by){
        return driver.findElements(by);
    }
定位方法:ID、CSS、Xpath
元素节点交互:
.click()
.clear()
.sendKeys("")
网页交互
navigate().to()  //打开指定的网页
navigate().back()  //后退
navigate().forward()  //前进
navigate().refresh()  //刷新
动作链action,比如:拖拽
Actions action = new Actions(webdriver);
//source-要拖动的元素A,target-拖动元素A到达的目标元素
action.dragAndDrop(source, target);
//source-要拖动的元素A,拖动元素移动多少,标准以元素A左上角为准,拖动元素相对元素A移到右边是x是正值,左边是负值,拖动元素相对元素A移到上边是y是负值,下边是正值,
action.dragAndDropBy(source, xOffset, yOffset);

参考文章

执行js:指定页面滚动
String js = "document.documentElement.scrollTop=2000";
((JavascriptExecutor)driver).executeScript(js);
获取节点信息
.getText();  //获取文本信息
.getAttribute("");  //获取属性信息
.getCssValue("");  //css信息
.getLocation();  //位置信息
.getTagName();   //标签名称
.getSize();  //节点大小

切换frame

driver.switchTo().frame(0);

切换handle

driver.switchTo().window((String)driver.getWindowHandles().toArray()[1]);

隐式等待(设置等待#s)

driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);

显式等待(持续等待*s,知道出现可使用的元素)

new WebDriverWait(driver,5)
.until(ExpectedConditions.elementToBeClickable(By.name("q")));

截图

File file = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);

选项卡管理

Set<String> windowsHandles = driver.getWindowHandles();
        for (String s : windowsHandles) {
            if (s.equals("111")){
                driver.switchTo().window(s);
                break;
            }
            
        }

文件导入

public ContactPage importFromFile(String path){
        try {
            Thread.sleep(2000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        findElement(By.partialLinkText("批量导入/导出"),0).click();
        findElement(By.linkText("文件导入"),2).click();
        try {
            Thread.sleep(2000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        findElement(By.id("js_upload_file_input")).sendKeys(path);
        findElement(By.id("submit_csv")).click();
        return this;
    }

弹窗类型
1)ajax:直接定位即可、2)iframe:switchTo、3)打开新窗口switchTo、4)alert或Confirm:先定义窗口,再定位关键字。

上传图片

testcase逻辑:

业务流程处理

断言

assertThat(msgTitlekjukj,hasItem(title));
Assert.assertTrue("登录失败,密码错误",  webdriver.getCurrentUrl().contains("staffLogin"));
Assert.assertFalse("密码修改失败",webDriver.getCurrentUrl().contains("staffLogin"));
assertEqual(a,b,[msg='测试失败时打印的信息']): 断言a和b是否相等,相等则测试用例通过。

assertNotEqual(a,b,[msg='测试失败时打印的信息']): 断言a和b是否相等,不相等则测试用例通过。

assertTrue(x,[msg='测试失败时打印的信息']): 断言x是否True,是True则测试用例通过。

assertFalse(x,[msg='测试失败时打印的信息']): 断言x是否False,是False则测试用例通过。

assertIs(a,b,[msg='测试失败时打印的信息']): 断言a是否是b,是则测试用例通过。

assertNotIs(a,b,[msg='测试失败时打印的信息']): 断言a是否是b,不是则测试用例通过。

assertIsNone(x,[msg='测试失败时打印的信息']): 断言x是否None,是None则测试用例通过。

assertIsNotNone(x,[msg='测试失败时打印的信息']): 断言x是否None,不是None则测试用例通过。

assertIn(a,b,[msg='测试失败时打印的信息']): 断言a是否在b中,在b中则测试用例通过。

assertNotIn(a,b,[msg='测试失败时打印的信息']): 断言a是否在b中,不在b中则测试用例通过。

assertIsInstance(a,b,[msg='测试失败时打印的信息']): 断言a是是b的一个实例,是则测试用例通过。

assertNotIsInstance(a,b,[msg='测试失败时打印的信息']): 断言a是是b的一个实例,不是则测试用例通过。

数据清理:可以借助数据驱动,可以在testcase
针对add、alter数据进行清理
add–>delete
alter–>再alter

时间控件的设计:借助js

String js = "document.getElementById(日期输入框ID).value='" +"2020"+ "'";
((JavascriptExecutor)driver).executeScript(js);

设计测试用例:参考ui用例逻辑

1.输入参数的组合,前端判断逻辑校验;
2.正常流程校验是否可以通过,此处可以不过多做数据层面的校验

关于Junit的功能

1.参数化测试

@ParameterizedTest
@CsvFileSource(resources = "TestUserApi.csv")

2.注解:测试用例整理

@Test

@BeforeAll:举例在所有的testcase执行前需要进行登录获取cookie操作。

@AfterAll:举例在所有testcase执行结束需要调用driver.quit方法。

@RepeatedTest(#)重复执行#遍

@displayName()展示名称

@Nested 先执行主类,再将后面的倒序执行

@Disabled 跳过但提示执行完成

3.suite体系管理用例的顺序

@RunWith(JUnitPlatform.class)
    @SelectPackages({"TestcaseSuite"})
    @IncludePackages({
        "TestcaseSuite.case1.TestRun1",
        "TestcaseSuite.case2.TestRun2"
        })
@RunWith(Suite.class)
    @Suite.SuiteClasses({
            TestcaseSuite.case1.TestRun1.class
    })
发布了16 篇原创文章 · 获赞 0 · 访问量 582

猜你喜欢

转载自blog.csdn.net/LittleGirl_orBoy/article/details/104643020