jck28-lucio-【实战】电子商务产品实战

目录

  • 产品分析
  • 测试用例分析
  • 编写脚本
  • 脚本优化
  • 生成测试报告

产品分析

  • 产品:litemall管理后台
  • 功能:商品类目
  • 使用账户
    • 用户名: manage
    • 密码: manage123
      litemall

测试用例分析

编写脚本思路

image

前置后置

  • 在BeforeAll打开浏览器
  • AfterAll关闭浏览器进程
  • 添加隐式等待配置
public class LitemallTest {
    private static WebDriver driver;

    @BeforeAll
    public static void setUpClass() {
        driver = new ChromeDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
    }

    @AfterAll
    public static void tearDownClass() {
        driver.quit();
    }
}

初步实现功能

  • 登录功能
  • 新增功能
  • 删除功能
  • 整体调试
public class LitemallTest {
    private static WebDriver driver;
    @BeforeAll
    public static void setUpClass() {
        driver = new ChromeDriver();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        driver.get("https://litemall.hogwarts.ceshiren.com");
        driver.findElement(By.name("username")).clear();
        driver.findElement(By.name("username")).sendKeys("manage");
        driver.findElement(By.name("password")).clear();
        driver.findElement(By.name("password")).sendKeys("manage123");
        driver.findElement(By.xpath("//*[text()='登录']")).click();
    }

    @AfterAll
    public static void tearDownClass() {
        driver.quit();
    }

    @Test
    void addProductType() throws InterruptedException {
        driver.findElement(By.xpath("//*[text()='商场管理']")).click();
        driver.findElement(By.xpath("//*[text()='商品类目']")).click();
        driver.findElement(By.xpath("//*[text()='添加']")).click();
        driver.findElement(By.cssSelector(".el-input__inner")).sendKeys("添加商品操作");
        Thread.sleep(2000);
        driver.findElement(By.cssSelector(".dialog-footer .el-button--primary")).click();
        List<WebElement> eles = driver.findElements(By.xpath("//*[text()='添加商品操作']"));
        driver.findElement(By.xpath("//*[text()='添加商品操作']/../..//*[text()='删除']")).click();
        assertEquals(eles.size(), 0);
    }

    @Test
    void deleteProductType() throws InterruptedException {
        driver.findElement(By.xpath("//*[text()='商场管理']")).click();
        driver.findElement(By.xpath("//*[text()='商品类目']")).click();
        driver.findElement(By.xpath("//*[text()='添加']")).click();
        driver.findElement(By.cssSelector(".el-input__inner")).sendKeys("删除商品操作");
        Thread.sleep(2000);
        driver.findElement(By.cssSelector(".dialog-footer .el-button--primary")).click();
        driver.findElement(By.xpath("//*[text()='删除商品操作']/../..//*[text()='删除']")).click();
        Thread.sleep(2000);
        List<WebElement> eles = driver.findElements(By.xpath("//*[text()='删除商品操作']"));
        assertEquals(eles.size(), 0);
    }
}

代码优化

  • 强制等待全部替换为显式等待
  • 使用ExpectedConditions提供的方法
  • 自定义显式等待条件
  • 注意:代码片段,不要直接复制粘贴
// 初始化 显式等待 和流等待实例
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
fluentWait = new FluentWait<WebDriver>(driver)
    //设置等待评估条件为真的时间 ---超时值
    .withTimeout(Duration.ofSeconds(30))
    //设置评估条件的频率 ---轮询频率
    .pollingEvery(Duration.ofMillis(500))
    //忽略特定类型的异常
    .ignoring(ElementClickInterceptedException.class);
// 流等待
fluentWait.until(driver1 -> {
    System.out.println("click and create");
    driver1.findElement(By.cssSelector(".dialog-footer .el-button--primary")).click();
    return driver1.findElement(By.cssSelector(".el-notification__title"));
});
// 显式等待
Boolean res = wait.until(ExpectedConditions.
        invisibilityOfElementLocated((By.xpath("//*[text()='删除商品操作']"))));

添加日志

  • 日志配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- name指定<appender>的名称    class指定<appender>的全限定名  ConsoleAppender的作用是将日志输出到控制台-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--            输出时间格式-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36}.%M\(%line\) -- %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="com.ceshiren" level="DEBUG" />
    <logger name="com" level="WARN" />
    <logger name="ceshiren" level="WARN" />
    <logger name="org" level="WARN" />

    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

添加截图

  • getScreenshotAs 方法
  • 提前创建图片保存路径
void saveScreen() throws IOException {
    // 生成时间戳
    long nowTime = System.currentTimeMillis();
    // 保存文件
    File currentScreen = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    FileUtils.copyFile(currentScreen, new File("./files/"+nowTime+".png"));
    // 添加allure附件
    Allure.addAttachment("add picture", "image/png",
            new FileInputStream("./files/"+tmNow+".png"),".jpg");
}

生成测试报告-前提条件

  • 前提条件:
    • 安装Allure程序
    • 安装allure-pytest插件
    • 安装maven相关运行依赖
<build>
        <!-- maven 运行的依赖插件 -->
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <parameters>true</parameters>
                    <source>11</source>
                    <target>11</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M7</version>
                <configuration>
                    <includes>
                        <include>**/*Test.java</include>
<!--                        <include>**/**/LitemallTest.java</include>-->
                    </includes>
                </configuration>
            </plugin>
        </plugins>
    </build>

<!-- allure依赖 -->
<dependency>
    <groupId>io.qameta.allure</groupId>
    <artifactId>allure-junit5</artifactId>
    <version>2.13.6</version>
    <scope>test</scope>
</dependency>

生成测试报告-执行命令

执行测试用例,生成测试报告数据

mvn clean test -Dtest=测试类名/包名

生成测试报告在线地址

allure serve ./allure-results/

目前脚本存在的问题

  • 很多重复代码,维护困难
  • 没有办法清晰的描述业务场景
    学习PO设计模式之后解决这些问题