User Management System-Automated Testing

1. Mind map to write web automation test cases

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-5pmewL7O-1681561315211) (C:\Users\28463\AppData\Roaming\Typora\typora-user-images\ 1681560620352.png)]

2. Create a test project

  1. Create a Maven project
  2. Write relevant test code under the test package
  3. Import related dependencies needed for automated testing

Introduce automated test-related dependencies in pom.xml:

    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.0.0</version>
        </dependency>
        <!-- 保存屏幕截图文件需要用到的包-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <!-- Junit 中 参数化测试 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <!-- junit 中 测试套件 -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>1.8.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

3. Design user management system automation test cases according to the mind map

3.1 Prepare tools

Create the AutoTestUtils class under the common package, which needs to provide the following functions:

  1. Create a driver object and provide it to the page.
  2. Create an implicit wait, acting on the entire life cycle of the driver object.
  3. Provides screenshot methods and formats for saving screenshots.
/**
 * @Description: 创建驱动对象;提供屏幕截图方法
 * @Date 2023/4/15 9:59
 * @Author:
 */
public class AutoTestUtils {
    
    
    public static EdgeDriver driver;

    /**
     * @param : 创建驱动对象
     * @return EdgeDriver
     * @description TODO
     */
    public static EdgeDriver createDriver() {
    
    
        EdgeOptions options = new EdgeOptions();
        options.addArguments("-remote-allow-origins=*");
        // 驱动对象没有创建
        if(driver == null) {
    
    
            driver = new EdgeDriver(options);
            // 创建隐式等待
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
        }
        // 驱动对象已经创建好了
        return driver;
    }

    /**
     * @param str: 类名
     * @return void
     * @description 获取屏幕截图,把所有的用例执行的结果都保存下来
     */
    public void getScreenShot(String str) throws IOException {
    
    
        List<String> list = getTime();
        // ./src/test/java/com/usermanagerWebAutoTest/日期/类名_日期_时间.png
        String filename = "./src/test/java/com/usermanagerWebAutoTest/" + list.get(0) +
                "/" + str + "_" + list.get(1) + ".png";
        // 进行屏幕截图
        File srcFile = driver.getScreenshotAs(OutputType.FILE);
        // 将屏幕截图生成的图片放到指定路径下
        FileUtils.copyFile(srcFile,new File(filename));
    }

    public List<String> getTime() {
    
    
        // 文件格式 2023-04-15/2023-04-15_12:36:00
        SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sim2 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
        // 以天的维度按文件夹进行保存
        String dirname = sim1.format(System.currentTimeMillis());
        String filename = sim2.format(System.currentTimeMillis());
        List<String> list = new ArrayList<>();
        list.add(dirname);
        list.add(filename);
        return list;
    }
}

Create the DriverQuitTest class under the Tests package, the main function of this class is to release the driver

/**
 * @Description: 释放驱动
 * @Date 2023/4/15 9:59
 * @Author:
 */
public class DriverQuitTest extends AutoTestUtils {
    
    
    public static EdgeDriver driver = createDriver();

    @Test
    void driverQuit() {
    
    
        driver.quit();
    }
}

Create a runSuite class under the Tests package, which is the test suite

/**
 * @Description: 测试套件
 * @Date 2023/4/15 10:00
 * @Author:
 */
@Suite
@SelectClasses({
    
    UserNoLoginTest.class,UserLoginTest.class,UserListTest.class,AddUserTest.class,UpdateUserTest.class,DriverQuitTest.class})
public class runSuite {
    
    
}

3.2 Test the login page

Create a UserLoginTest class with 6 test cases.

  • Whether the page can be opened normally
  • Do not enter a user name, enter a password, and click Login
  • Enter the user name, do not enter the password, click Login
  • Enter neither username nor password, click Login
  • Enter the wrong username and password, click Login
  • Enter the correct username and password, click Login
/**
 * @Description: 测试登录页面
 * @Date 2023/4/15 10:00
 * @Author:
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserLoginTest extends AutoTestUtils {
    
    
    // 1. 访问浏览器对象  2. 访问登录页面的 URL
    public static EdgeDriver driver = createDriver();

    @BeforeAll
    static void baseControl() {
    
    
        driver.get("http://47.108.57.239:8080/login.html");
    }

    /**
     * @param :
     * @return void
     * @description 检查页面是否可以正常打开
     */
    @Test
    @Order(1)
    void loginPageLoadRight() throws IOException {
    
    
        driver.findElement(By.cssSelector("#body > div > h3"));
        driver.findElement(By.cssSelector("#loginname"));
        driver.findElement(By.cssSelector("#submit"));
        getScreenShot(getClass().getName());
    }

    /**
     * @param password:
     * @return void
     * @description 不输入用户名,输入密码,点击登录
     */
    @ParameterizedTest
    @CsvSource({
    
    "111"})
    @Order(2)
    void loginFailUsernameNull(String password) throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
        driver.findElement(By.cssSelector("#password")).clear();

        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        // 登录失败结果检测
        Thread.sleep(1000);
        // 切换到弹窗进行处理
        Alert alert = driver.switchTo().alert();
        // 点击确认
        alert.accept();
        getScreenShot(getClass().getName());
    }

    /**
     * @param username:
     * @return void
     * @description 输入用户名,不输入密码,点击登录
     */
    @ParameterizedTest
    @CsvSource({
    
    "111"})
    @Order(3)
    void loginFailPasswordNull(String username) throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
        driver.findElement(By.cssSelector("#password")).clear();

        driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
        driver.findElement(By.cssSelector("#submit")).click();
        // 登录失败结果检测
        Thread.sleep(1000);
        // 切换到弹窗进行处理
        Alert alert = driver.switchTo().alert();
        // 点击确认
        alert.accept();
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description 用户名和密码都不输入,点击登录
     */
    @Test
    @Order(4)
    void loginFailUsernameAndPasswordNull() throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
        driver.findElement(By.cssSelector("#password")).clear();

        driver.findElement(By.cssSelector("#submit")).click();
        // 登录失败结果检测
        Thread.sleep(1000);
        // 切换到弹窗进行处理
        Alert alert = driver.switchTo().alert();
        // 点击确认
        alert.accept();
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description 输入错误的用户名和密码,点击登录
     */
    @ParameterizedTest
    @CsvSource({
    
    "1111,1111"})
    @Order(5)
    void loginFail(String username,String password) throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
        driver.findElement(By.cssSelector("#password")).clear();

        driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        // 登录失败结果检测
        Thread.sleep(1000);
        // 切换到弹窗进行处理
        Alert alert = driver.switchTo().alert();
        // 点击确认
        alert.accept();
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description 输入正确的用户名和密码,点击登录
     */
    @ParameterizedTest
    @CsvSource({
    
    "admin,admin"})
    @Order(6)
    void loginSucced(String username,String password) throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#loginname")).clear(); // 先清空一下
        driver.findElement(By.cssSelector("#password")).clear();

        driver.findElement(By.cssSelector("#loginname")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        // 登录成功检测,如果跳转到用户列表页,才算是成功的
        driver.findElement(By.cssSelector("#body > div > h3"));
        Thread.sleep(2000);
        getScreenShot(getClass().getName());
        // 这里页面跳转了,重新返回到登录页面
        driver.navigate().back();
    }
}

3.3 Test user list page

Create the UserListTest class, which has 4 test cases (in the default login state).

  • Whether the content of the page is displayed normally
  • Is it possible to jump to the add user page
  • Whether to jump to modify user page
  • Query whether the user function is normal
/**
 * @Description: 测试用户列表页
 * @Date 2023/4/15 10:00
 * @Author:
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserListTest extends AutoTestUtils {
    
    
    public static EdgeDriver driver = createDriver();

    @BeforeAll
    static void baseControl() {
    
    
        driver.get("http://47.108.57.239:8080/list.html");
    }

    /**
     * @return void
     * @description 检查页面内容显示是否正常
     */
    @Test
    @Order(1)
    void ListPageLoadRight() throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#submit1"));
        driver.findElement(By.cssSelector("#body > div > table > tbody:nth-child(1) > tr > th:nth-child(1)"));
        driver.findElement(By.cssSelector("#all > li:nth-child(1) > a"));
        driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > a:nth-child(1)"));
        driver.findElement(By.cssSelector("#delete"));
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description: 检测添加用户按钮链接跳转正常
     */
    @Test
    @Order(2)
    void LinkJumpAdd() throws IOException, InterruptedException {
    
    
        driver.findElement(By.cssSelector("#body > div > div:nth-child(3) > a:nth-child(1)")).click();
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
        driver.navigate().back();
    }

    /**
     * @return void
     * @description: 检测修改用户按钮链接跳转正常
     */
    @Test
    @Order(3)
    void LinkJumpUpdate() throws IOException, InterruptedException {
    
    
        driver.findElement(By.cssSelector("#info > tr:nth-child(1) > th:nth-child(10) > a:nth-child(1)")).click();
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
        driver.navigate().back();
    }

    /**
     * @return void
     * @description: 检测查询用户功能是否正常
     */
    @ParameterizedTest
    @CsvSource({
    
    "超级管理员"})
    @Order(4)
    void SelectUser(String name) throws IOException, InterruptedException {
    
    
        driver.findElement(By.cssSelector("#ipt_name")).sendKeys(name);
        driver.findElement(By.cssSelector("#submit1")).click();
        driver.findElement(By.cssSelector("#info > tr > th:nth-child(3)"));
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
    }
}

3.4 Test adding user page

Create the AddUserTest class, which has 5 test cases (in the default login state).

  • Whether the page content is displayed normally
  • The administrator authority is super management. When filling in the user information, if the user name is repeated, it cannot be submitted.
  • The administrator authority is super management. When filling in the user information, if the user name is not repeated, it can be submitted.
  • Administrator rights are ordinary users, who can fill in information normally, but cannot submit.
  • The back link jumps fine.
/**
 * @Description: 测试添加用户页
 * @Date 2023/4/15 10:00
 * @Author:
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AddUserTest extends AutoTestUtils {
    
    
    public static EdgeDriver driver = createDriver();

    @BeforeAll
    static void baseControl() {
    
    
        driver.get("http://47.108.57.239:8080/add.html");
    }

    /**
     * @return void
     * @description 检查页面内容显示是否正常
     */
    @Test
    @Order(1)
    void AddPageLoadRight() throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#username"));
        driver.findElement(By.cssSelector("#password"));
        driver.findElement(By.cssSelector("#btn_sub"));
        driver.findElement(By.cssSelector("#btn_back"));
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description :管理员权限为超管,填写用户信息时,如果用户名重复,不能提交。
     */
    @ParameterizedTest
    @CsvSource({
    
    "111,111,111,111,20,111,111"})
    @Order(2)
    void SuperTube_UserRepeatFail(String user,String login,String pass,String pass2,String age,String qq,String em) throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#username")).sendKeys(user);
        driver.findElement(By.cssSelector("#loginname")).sendKeys(login);
        driver.findElement(By.cssSelector("#password")).sendKeys(pass);
        driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
        driver.findElement(By.cssSelector("#age")).sendKeys(age);
        driver.findElement(By.cssSelector("#qq")).sendKeys(qq);
        driver.findElement(By.cssSelector("#email")).sendKeys(em);
        driver.findElement(By.cssSelector("#btn_sub")).click();
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description :管理员权限为超管,填写用户信息时,如果用户名不重复,可以提交。
     */
    @ParameterizedTest
    @CsvSource({
    
    "111,111,20,111,111"})
    @Order(3)
    void SuperTube_UserRepeatSucc(String pass,String pass2,String age,String qq,String em) throws InterruptedException, IOException {
    
    
        Random random = new Random();
        int n = random.nextInt(100000);
        driver.findElement(By.cssSelector("#username")).sendKeys(String.valueOf(n));
        driver.findElement(By.cssSelector("#loginname")).sendKeys(String.valueOf(n));
        driver.findElement(By.cssSelector("#password")).sendKeys(pass);
        driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
        driver.findElement(By.cssSelector("#age")).sendKeys(age);
        driver.findElement(By.cssSelector("#qq")).sendKeys(qq);
        driver.findElement(By.cssSelector("#email")).sendKeys(em);
        driver.findElement(By.cssSelector("#btn_sub")).click();
        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
        Thread.sleep(1000);
        Alert alert2 = driver.switchTo().alert();
        alert2.dismiss();
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
        driver.navigate().back();
    }

    /**
     * @return void
     * @description: 返回链接跳转正常。
     */
    @Test
    @Order(4)
    void ReturnLinkJumpSucc() throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#btn_back")).click();
        driver.findElement(By.cssSelector("#body > div > h3"));
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
    }
}

3.5 Test and modify the user page

Create the UpdateUserTest class, which has 5 test cases (in the default login state).

  • Whether the page content is displayed normally.
  • The administrator authority is super management. When modifying user information, if the password and the confirmation password column are different, the submission cannot be submitted.
  • The administrator authority is super management. When modifying user information, if the password and the confirmation password column are the same, you can submit it.
  • Administrator rights are ordinary users, who can modify information normally, but cannot submit.
  • The back link jumps fine, and the reset button functions fine.
/**
 * @Description: 测试修改用户页
 * @Date 2023/4/15 10:01
 * @Author:
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UpdateUserTest extends AutoTestUtils {
    
    

    public static EdgeDriver driver = createDriver();

    @BeforeAll
    static void baseControl() {
    
    
        driver.get("http://47.108.57.239:8080/update.html?uid=3");
    }

    /**
     * @return void
     * @description 检查页面内容显示是否正常
     */
    @Test
    @Order(1)
    void AddPageLoadRight() throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#body > div > h3"));
        String text = driver.findElement(By.cssSelector("#loginname")).getAttribute("value");
        Assertions.assertEquals("111",text);
        driver.findElement(By.cssSelector("#btn_sub"));
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description :管理员权限为超管,修改用户信息时,如果密码和确认密码栏不相同,不能提交。
     */
    @ParameterizedTest
    @CsvSource({
    
    "1234,111,111666"})
    @Order(2)
    void SuperTube_PassInequalityFail(String pass,String pass2,String em) throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#password")).sendKeys(pass);
        driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
        driver.findElement(By.cssSelector("#email")).sendKeys(em);
        driver.findElement(By.cssSelector("#btn_sub")).click();
        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
        Thread.sleep(1000);
        getScreenShot(getClass().getName());
        driver.findElement(By.cssSelector("#btn_reset")).click();
    }

    /**
     * @return void
     * @description :管理员权限为超管,修改用户信息时,如果密码和确认密码栏相同,可以提交。
     */
    @ParameterizedTest
    @CsvSource({
    
    "234567,234567,1111111"})
    @Order(3)
    void SuperTube_PassIdenticalSucc(String pass,String pass2,String em) throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#password")).sendKeys(pass);
        driver.findElement(By.cssSelector("#password2")).sendKeys(pass2);
        driver.findElement(By.cssSelector("#email")).sendKeys(em);
        driver.findElement(By.cssSelector("#btn_sub")).click();
        Thread.sleep(1000);
        Alert alert = driver.switchTo().alert();
        alert.accept();
        getScreenShot(getClass().getName());
        driver.navigate().back();
    }

    /**
     * @return void
     * @description: 返回链接跳转正常。
     */
    @Test
    @Order(4)
    void ReturnLinkJumpSucc() throws InterruptedException, IOException {
    
    
        driver.findElement(By.cssSelector("#btn_back")).click();
        String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
        Assertions.assertEquals("用户信息列表",text);
        getScreenShot(getClass().getName());
    }
}

3.6 Not logged in

Create a UserNoLoginTest class with three test cases.

  • Jump to user list page.
  • Jump to the Add User page.
  • Jump to edit user page.
/**
 * @Description: 测试未登录状态下
 * @Date 2023/4/15 10:01
 * @Author:
 */
public class UserNoLoginTest extends AutoTestUtils {
    
    
    public static EdgeDriver driver = createDriver();

    /**
     * @param :
     * @return void
     * @description 未登录状态跳转到用户列表页
     */
    @Test
    void JumpUserListFail() throws InterruptedException, IOException {
    
    
        driver.get("http://47.108.57.239:8080/list.html");
        Thread.sleep(1000);
        String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
        Assertions.assertEquals("管理员登录",text);
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description 未登录状态跳转到添加用户页
     */
    @Test
    void JumpAddUserFail() throws InterruptedException, IOException {
    
    
        driver.get("http://47.108.57.239:8080/add.html");
        Thread.sleep(1000);
        String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
        Assertions.assertEquals("管理员登录",text);
        getScreenShot(getClass().getName());
    }

    /**
     * @return void
     * @description 未登录状态跳转到修改用户页
     */
    @Test
    void JumpUpdateUserFail() throws InterruptedException, IOException {
    
    
        driver.get("http://47.108.57.239:8080/update.html");
        Thread.sleep(1000);
        String text = driver.findElement(By.cssSelector("#body > div > h3")).getText();
        Assertions.assertEquals("管理员登录",text);
        getScreenShot(getClass().getName());
    }
}

4. Summary of automated testing projects

4.1 Implementation steps of automated test project

  1. According to your own project, use a mind map to design UI automation test cases;
  2. Combined with the test cases written by myself, use the Selenium4 automated testing tool and the Junit5 unit test frame framework to realize Web automated testing;
  3. Then there is the module division, which is mainly divided into two packages, one is the tool class package, which is used to create the driver object and provide the screenshot method, and the other package is the test case package, and the classes under this package are based on the page as the The test code written by the unit avoids the trouble of creating a driver object for each method, and finally adds these test classes to the test suite.
  4. Be careful not to wait for the entire code of the project to be written before testing it. It is best to write a part of the code and test it. For example, when I write code, I write a test case for a page, and then test it.

4.2 Current project highlights

  • Only create the driver object once, avoiding the waste of time and resources caused by repeatedly creating the driver object for each use case
  • Use the annotations provided in Junit5: Avoid generating too many objects, causing waste of resources and time, and improving the efficiency of automated execution
  • Test suite: Reduce the workload of testers, execute all test cases to be run at once through the suite
  • Waiting is used: implicit waiting + mandatory waiting (improves the efficiency of automation and improves the stability of automation)
  • Use screenshots: facilitate the traceability of problems and the resolution of problems
  • Use parameterization: keep use cases concise and improve code readability

Guess you like

Origin blog.csdn.net/m0_58761900/article/details/130174754