宣纸阁项目测试报告


一、项目背景

宣纸阁是一种基于互联网的社群交流平台,旨在为用户提供信息共享、观点讨论与兴趣互动的空间。其核心理念是通过结构化的话题组织和用户参与,构建开放、有序的在线社区生态。本项目致力于打造一个功能全面、界面简洁的现代化网络社区平台,旨在为用户搭建高效连接桥梁,促进知识共享,并汇聚志同道合的兴趣群体。

二、项目功能

  1. 注册页面:用户可通过输入有效的用户名和密码完成注册,注册成功后将自动跳转至登录页面。
  2. 登录页面:用户输入正确的用户名和密码即可登录,登录成功后将进入帖子列表页面。
  3. 帖子列表页面:用户可在选定板块中浏览帖子列表,点击任意帖子即可查看详情;通过"发布帖子"按钮进入编辑页面;点击个人头像后,选择"我的帖子"可查看个人发帖记录,选择"个人中心"可进入个人主页,选择"退出登录"可完成账号登出;页面右上角设有搜索框,支持帖子检索。管理员用户额外享有板块管理权限,可进行板块的增删操作。
  4. 帖子详情页面:管理员和作者可对帖子及回复进行编辑和删除操作;所有注册用户均享有向作者发送站内信、为帖子点赞以及参与回复的基本功能。
  5. 帖子编辑页面:用户可在此发布新内容。
  6. 站内信:点击页面右上角的铃铛图标,即可查看站内消息。通过该功能,用户不仅可以接收信息,还能便捷地发送和回复站内信。
  7. 个人帖子页面:展示用户发布的所有帖子。
  8. 个人中心页面:用户可以修改昵称、密码、邮箱地址、电话号码以及个人简介。

三、测试计划

在这里插入图片描述

1. 功能测试

1.1 注册页面

1.1.1 正常注册

  • 输入合法用户名和密码,点击注册——显示注册成功
    在这里插入图片描述

1.1.2 异常注册

  • 未输入账号和密码,点击注册——显示注册失败
    在这里插入图片描述

  • 输入账号,但是未输入密码,点击注册——显示注册失败
    在这里插入图片描述

  • 未输入账号,但是输入密码,点击注册——显示注册失败
    在这里插入图片描述

  • 输入已注册的账号,输入密码,点击登录——显示注册失败
    在这里插入图片描述

1.2 登录页面

1.2.1 正常登录

  • 输入正确的账号和密码,点击登录——显示登录成功
    在这里插入图片描述

1.2.2 异常登录

  • 未输入账号和密码。点击登录——显示登录失败
    在这里插入图片描述

  • 输入账号但是未输入密码,点击登录——显示登录失败
    在这里插入图片描述

  • 未输入账号但是输入密码,点击登录——显示登录失败
    在这里插入图片描述

  • 输入正确的账号,错误的密码,点击登录——显示登录失败
    在这里插入图片描述

1.3 帖子列表页面

1.3.1 帖子列表页面是否正常

  • 若用户为管理员,是否显示新增板块和删除板块按钮
    在这里插入图片描述

  • 若用户为普通用户,是否显示新增板块和删除板块按钮
    在这里插入图片描述

  • 点击不同板块,帖子列表展示是否正常
    在这里插入图片描述

  • 搜索框中输入内容,搜索结果是否正常
    在这里插入图片描述

1.3.2 页面跳转

  • 点击帖子标题,是否能进入对应的帖子详情页面
    成功在这里插入图片描述

  • 点击小铃铛图标,是否进入站内信页面
    成功在这里插入图片描述

  • 点击个人头像 → 点击我的帖子,是否进入我的帖子页面
    成功在这里插入图片描述

  • 点击个人头像 → 点击个人中心,是否进入个人中心页面
    成功在这里插入图片描述

  • 点击个人头像 → 点击退出登录,是否跳转到登录页面
    成功在这里插入图片描述

1.4 帖子详情页面

1.4.1 功能验证

  • 用户是否可以回复帖子
    在这里插入图片描述

  • 用户是否可以点赞帖子
    在这里插入图片描述

  • 点击发私信按钮,是否可以发送站内信
    在这里插入图片描述

1.4.2 权限验证

  • 若用户为作者或管理,编辑按钮和删除按钮是否正常显示
    作者:在这里插入图片描述
    管理:在这里插入图片描述

  • 若用户不是作者或管理,编辑按钮和删除按钮是否隐藏
    在这里插入图片描述

1.5 帖子编辑页面

1.5.1 正常编辑

  • 输入标题,输入内容,点击提交——发布成功
    在这里插入图片描述

1.5.2 异常编辑

  • 不输入标题,不输入内容,点击提交——发布失败
    在这里插入图片描述

  • 输入标题,不输入内容,点击提交——发布失败
    在这里插入图片描述

1.6 站内信

1.6.1 发送功能

  • 不输入内容,点击提交——发送失败
    在这里插入图片描述

  • 输入内容,点击提交——发送成功
    在这里插入图片描述

1.6.2 回复功能

  • 不输入内容,点击提交——回复失败
    在这里插入图片描述
  • 输入内容,点击提交——回复成功
    在这里插入图片描述
    在这里插入图片描述

2. 自动化测试

2.1 功能测试

在这里插入图片描述

2.1.1 枚举类
package com.example.forum.auto.common;

/**
 * @author hanzishuai
 * Blog :  https://blog.csdn.net/qrwitu142857
 * @date 2025/5/12 14:58
 * @Description
 */
public enum BrowserName {
    CHROME("chrome"),
    EDGE("edge");

    String browserName;

    public String getBrowserName() {
        return browserName;
    }

    BrowserName(String browserName) {
        this.browserName = browserName;
    }

}

2.1.2 创建浏览器驱动类
package com.example.forum.auto.common;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;

/**
 * @author hanzishuai
 * Blog :  https://blog.csdn.net/qrwitu142857 [原文地址,请尊重原创]
 * @date 2025/4/20 22:22
 * @Description
 */
public class Utils {
    public static WebDriver driver = null;

    public WebDriverWait wait;


    /**
     * Created by hanzishuai on 2025/4/20
     *
     * @param
     * @return void
     * @Description 创建 Driver
     */
    private WebDriver createChromeDriver() {
        if (driver == null) {
            WebDriverManager.chromedriver().setup();
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--remote-allow-origins=*");
            driver = new ChromeDriver(options);

            // 隐式等待
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));
        }

        return driver;
    }

    private WebDriver createEdgeDriver() {
        if (driver == null) {
            WebDriverManager.edgedriver().setup();
            EdgeOptions options = new EdgeOptions();
            options.addArguments("--remote-allow-origins=*");
            driver = new EdgeDriver(options);

            // 隐式等待
            driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));
        }
        return driver;
    }

    public Utils(String url) {
        if(driver == null) {
            driver = createChromeDriver();
            driver.get(url);
        }
        wait = new WebDriverWait(driver, Duration.ofSeconds(15));
        driver.manage().window().maximize();
    }

    public Utils(String url, BrowserName browserName) {
        if (browserName.getBrowserName().equals(BrowserName.EDGE.getBrowserName())) {
            driver = createEdgeDriver();
            driver.get(url);
        } else if (browserName.getBrowserName().equals(BrowserName.CHROME.getBrowserName())) {
            driver = createChromeDriver();
            driver.get(url);
        }
        wait = new WebDriverWait(driver, Duration.ofSeconds(15));
        driver.manage().window().maximize();
    }

    public void sleep() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    public void sleep(Long time) {
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Created by hanzishuai on 2025/4/20
     *
     * @param str 截图名称的前缀
     * @return
     * @Description 屏幕截图
     */
    public void screenShot(String str) throws IOException {
        // 设置文件名和图片名称格式
        SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS");
        String dirTime = sim1.format(System.currentTimeMillis());
        String fileTime = sim2.format(System.currentTimeMillis());

        String fileName = "src/test/java/com/example/forum/auto/images/" + dirTime + "/" + str + "_" + fileTime + ".png";

        // 截图
        File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(srcFile, new File(fileName));
    }

}

2.1.3 注册页面测试
package com.example.forum.auto.tests;


import com.example.forum.auto.common.BrowserName;
import com.example.forum.auto.common.Utils;
import lombok.NonNull;
import lombok.SneakyThrows;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.util.UUID;

/**
 * @author hanzishuai
 * Blog :  https://blog.csdn.net/qrwitu142857
 * @date 2025/5/11 22:16
 * @Description
 */
public class RegisterPage extends Utils {
    public static final String url = "http://82.157.200.90:58081/sign-up.html";

    public RegisterPage() {
        super(url);
    }

    public RegisterPage(BrowserName browserName) {
        super(url, browserName);
    }

    /**
     * Created by hanzishuai on 2025/5/11
     *
     * @Description 检查注册页面是否加载完毕
     */
    @SneakyThrows
    public void checkPageRight() {
        driver.findElement(By.cssSelector("#username"));
        driver.findElement(By.cssSelector("#nickname"));
        driver.findElement(By.cssSelector("#password"));
        driver.findElement(By.cssSelector("#passwordRepeat"));
        driver.findElement(By.cssSelector("#app > div:nth-child(6) > label > span"));
    }


    private void register(String username,String nickname,String passwordRepeat, String password,@NonNull Boolean policy) {
        // 将输入框清空
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#nickname")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#passwordRepeat")).clear();
        WebElement element = driver.findElement(By.cssSelector("#app > div:nth-child(6) > label > span"));
        if(element.isSelected()) {
            element.click();
        }


        // 输入账号密码,并点击提交
        if (username != null) {
            driver.findElement(By.cssSelector("#username")).sendKeys(username);
        }
        if(nickname != null) {
            driver.findElement(By.cssSelector("#nickname")).sendKeys(nickname);
        }
        if (password != null) {
            driver.findElement(By.cssSelector("#password")).sendKeys(password);
        }
        if (passwordRepeat != null) {
            driver.findElement(By.cssSelector("#passwordRepeat")).sendKeys(passwordRepeat);
        }
        if(policy) {
            WebElement element2 = driver.findElement(By.cssSelector("#app > div:nth-child(6) > label > span"));
            if(element2.isSelected()) {
                element2.click();
            }
        }

        driver.findElement(By.cssSelector("#submit")).click();
    }


    @SneakyThrows
    public void registerFail() {
        // 不输入账号和密码,点击提交
        register(null, null, null, null,false);
        register("test2", null, null, null,false);
        register("test2", "test2", null, null,false);
        register("test2", "test2", "123456", null,false);
        register("test2", "test2", "123456", "123",false);
        register("test2", "test2", "123456", "123456",false);
        register("awa", "awa", "123456", "123456",true);
    }

    @SneakyThrows
    public void registerSuccess() {
        String username = UUID.randomUUID().toString().replace("-", "").substring(0,7);

        register(username, username, "123456", "123456",true);

        // 截图
        screenShot("registerSuccess");

        // 注册成功会跳转到登录页面
        String text1 = driver.findElement(By.cssSelector("#submit")).getText();
        assert  "登录".equals(text1);
    }


    public void intoLoginPage() {
        WebElement element = driver.findElement(By.cssSelector("#app > div.text-center.text-muted.mt-3 > a"));
        wait.until(ExpectedConditions.elementToBeClickable(element));
        element.click();
    }
}

2.1.4 登录页面测试
package com.example.forum.auto.tests;

import com.example.forum.auto.common.BrowserName;
import com.example.forum.auto.common.Utils;
import lombok.SneakyThrows;
import org.openqa.selenium.By;

/**
 * @author hanzishuai
 * Blog :  https://blog.csdn.net/qrwitu142857
 * @date 2025/5/15 17:12
 * @Description
 */
public class LoginPage extends Utils {
    public static final String url = "http://82.157.200.90:58081/sign-in.html";

    public LoginPage(BrowserName browserName) {
        super(url, browserName);
    }

    public LoginPage() {
        super(url);
    }

    @SneakyThrows
    public void checkPageRight() {
        driver.findElement(By.cssSelector("#username"));
        driver.findElement(By.cssSelector("#password"));
        driver.findElement(By.cssSelector("#submit"));
    }

    private void login(String username, String password) {
        // 将输入框清空
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();

        // 输入账号密码,并点击提交
        if (username != null) {
            driver.findElement(By.cssSelector("#username")).sendKeys(username);
        }
        if (password != null) {
            driver.findElement(By.cssSelector("#password")).sendKeys(password);
        }

        driver.findElement(By.cssSelector("#submit")).click();
    }

    @SneakyThrows
    public void loginFail() {
        // 不输入账号和密码,点击提交
        login(null, null);


        // 输入账号,不输入密码,点击提交
        login("awa", null);


        // 不输入账号,输入密码,点击提交
        login(null, "123");

        screenShot("LoginFail");

        // 输入账号,输入错误的密码,点击提交
        login("awa", "12");

    }

    @SneakyThrows
    public void loginSuccess() {
        login("awa", "123456");

        // 如果登录成功会进入帖子列表页面
        driver.findElement(By.cssSelector("#article_list_board_title"));
    }
}
2.1.5 帖子列表测试
package com.example.forum.auto.tests;

import com.example.forum.auto.common.BrowserName;
import com.example.forum.auto.common.Utils;
import lombok.SneakyThrows;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.io.IOException;
import java.util.List;

/**
 * @author hanzishuai
 * Blog :  https://blog.csdn.net/qrwitu142857
 * @date 2025/5/15 17:46
 * @Description
 */
public class ArticleListPage extends Utils {
    public static final String url = "http://82.157.200.90:58081/index.html";

    public ArticleListPage(BrowserName browserName) {
        super(url, browserName);
    }

    public ArticleListPage() {
        super(url);
    }

    @SneakyThrows
    public void checkPageRight() {
        driver.findElement(By.cssSelector("#article_list_board_title"));
        driver.findElement(By.cssSelector("#search-input"));
        driver.findElement(By.cssSelector("#hzs-forum-content"));
    }

    public void changeBoard() {
        List<WebElement> elements = driver.findElements(By.cssSelector("#topBoardList span.nav-link-title"));
        for (WebElement element : elements) {
            element.click();
        }
        elements.get(0).click();
    }

    public void intoArticleDetail() throws IOException {
        try {
            WebElement element = driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong"));
            String text = element.getText();
            wait.until(ExpectedConditions.elementToBeClickable(element));
            Thread.sleep(500);
            element.click();
            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#details_article_title")));
            assert driver.findElement(By.cssSelector("#details_article_title")).getText().equals(text);
        } catch (Exception e) {
            screenShot("intoArticleDetailError");

        }
    }


    public void intoMyArticlePage() {

        WebElement element = driver.findElement(By.cssSelector("body > div.page > header.navbar.navbar-expand-md.navbar-light.d-print-none > div > div > div.nav-item.dropdown > a"));
        wait.until(ExpectedConditions.elementToBeClickable(element));
        sleep();
        element.click();
        WebElement element1 = driver.findElement(By.cssSelector("#index_user_settings"));
        sleep();
        wait.until(ExpectedConditions.elementToBeClickable(element1));
        element1.click();
    }

}

2.1.6 帖子详情页面测试
package com.example.forum.auto.tests;

import com.example.forum.auto.common.BrowserName;
import com.example.forum.auto.common.Utils;
import lombok.SneakyThrows;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.springframework.util.StringUtils;

/**
 * @author hanzishuai
 * Blog :  https://blog.csdn.net/qrwitu142857
 * @date 2025/5/15 19:30
 * @Description
 */
public class ArticleDetailPage extends Utils {

    public static final String url = "http://82.157.200.90:58081/index.html";

    public ArticleDetailPage(BrowserName browserName) {
        super(url, browserName);
    }

    public ArticleDetailPage() {
        super(url);
    }


    @SneakyThrows
    public void checkPageRight() {
        driver.findElement(By.cssSelector("#btn_details_send_message"));
        driver.findElement(By.cssSelector("#details_btn_like_count"));
        driver.findElement(By.cssSelector("#details_btn_article_reply"));
    }


    private void sendMessage(String content) {
        WebElement element = driver.findElement(By.cssSelector("#btn_details_send_message"));
        wait.until(ExpectedConditions.elementToBeClickable(element));
        element.click();

        WebElement element1 = driver.findElement(By.cssSelector("#index_message_receive_content"));
        wait.until(ExpectedConditions.elementToBeClickable(element1));
        if(StringUtils.hasLength(content)) {
            element1.sendKeys(content);
        }

        driver.findElement(By.cssSelector("#btn_index_send_message")).click();
    }

    public void sendMessageFail() {
        sendMessage(null);
        sendMessage("");
    }

    public void sendMessageSuccess() {
        sendMessage("test");
    }

}

2.1.7 个人中心测试
package com.example.forum.auto.tests;

import com.example.forum.auto.common.BrowserName;
import com.example.forum.auto.common.Utils;
import lombok.SneakyThrows;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;

/**
 * @author hanzishuai
 * Blog :  https://blog.csdn.net/qrwitu142857
 * @date 2025/5/15 18:07
 * @Description
 */
public class PersonalCenterPage extends Utils {
    public static final String url = "http://82.157.200.90:58081/index.html";


    public PersonalCenterPage() {
        super(url);
    }

    public PersonalCenterPage(BrowserName browserName) {
        super(url, browserName);
    }

    @SneakyThrows
    public void checkPageRight() {
        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#setting_input_nickname")));
        driver.findElement(By.cssSelector("#setting_input_nickname"));

        driver.findElement(By.cssSelector("#setting_submit_nickname"));
        wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#setting_submit_nickname")));

        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#setting_input_email")));
        driver.findElement(By.cssSelector("#setting_input_email"));
        wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#setting_submit_email")));
        driver.findElement(By.cssSelector("#setting_submit_email"));

        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#setting_input_phoneNum")));
        driver.findElement(By.cssSelector("#setting_input_phoneNum"));
        wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#setting_submit_phoneNum")));
        driver.findElement(By.cssSelector("#setting_submit_phoneNum"));

        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#settings_input_oldPassword")));
        driver.findElement(By.cssSelector("#settings_input_oldPassword"));
        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#settings_input_newPassword")));
        driver.findElement(By.cssSelector("#settings_input_newPassword"));
        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#settings_input_passwordRepeat")));
        driver.findElement(By.cssSelector("#settings_input_passwordRepeat"));
        wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#settings_submit_password")));
        driver.findElement(By.cssSelector("#settings_submit_password"));

        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#settings_textarea_remark")));
        driver.findElement(By.cssSelector("#settings_textarea_remark"));
        wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#settings_submit_remark")));
        driver.findElement(By.cssSelector("#settings_submit_remark"));
    }

    private void modify(String nickname, String email, String phoneNum, String oldPassword, String newPassword, String passwordRepeat, String remark) {
        checkPageRight();
        if (nickname != null) {
            driver.findElement(By.cssSelector("#setting_input_nickname")).clear();
            driver.findElement(By.cssSelector("#setting_input_nickname")).sendKeys(nickname);
            driver.findElement(By.cssSelector("#setting_submit_nickname")).click();
        }
        if (email != null) {
            driver.findElement(By.cssSelector("#setting_input_email")).clear();
            driver.findElement(By.cssSelector("#setting_input_email")).sendKeys(email);
            WebElement emailSubmitButton = driver.findElement(By.cssSelector("#setting_submit_email"));
            wait.until(ExpectedConditions.elementToBeClickable(emailSubmitButton));
            sleep();
            emailSubmitButton.click();
        }
        if (phoneNum != null) {
            driver.findElement(By.cssSelector("#setting_input_phoneNum")).clear();
            driver.findElement(By.cssSelector("#setting_input_phoneNum")).sendKeys(phoneNum);
            WebElement element = driver.findElement(By.cssSelector("#setting_submit_phoneNum"));
            wait.until(ExpectedConditions.elementToBeClickable(element));
            element.click();
        }
        if (oldPassword != null) {
            driver.findElement(By.cssSelector("#settings_input_oldPassword")).clear();
            driver.findElement(By.cssSelector("#settings_input_oldPassword")).sendKeys(oldPassword);
        }
        if (newPassword != null) {
            driver.findElement(By.cssSelector("#settings_input_newPassword")).clear();
            driver.findElement(By.cssSelector("#settings_input_newPassword")).sendKeys(newPassword);
        }
        if (passwordRepeat != null) {
            driver.findElement(By.cssSelector("#settings_input_passwordRepeat")).clear();
            driver.findElement(By.cssSelector("#settings_input_passwordRepeat")).sendKeys(passwordRepeat);
        }


        if (remark != null) {
            driver.findElement(By.cssSelector("#settings_textarea_remark")).clear();
            driver.findElement(By.cssSelector("#settings_textarea_remark")).sendKeys(remark);
            driver.findElement(By.cssSelector("#settings_submit_remark")).click();
        }

        if (oldPassword != null || newPassword != null || passwordRepeat != null) {
            driver.findElement(By.cssSelector("#settings_submit_password")).click();
        }

    }

    public void checkModify() {
        modify(null, null, null, null, null, null, null);
        modify("", "", "", "", "", "", "");
        modify("awa1", "abcdef@a.com", null, "123456", null, null, "个人介绍");
        modify("awa1", "abcdef@a.com", "123", "123456", null, null, "个人介绍");
        modify("awa1", "abcdef@a.com", null, "123456", "1234", null, "个人介绍");
        modify("awa1", "abcdef@a.com", null, "123456", "1234", "12", "个人介绍1");
        modify("awa", "abcdef@a.com", null, "123456", "1234", "12", "个人介绍1");
        modify("awa", "123456@qq.com", "123456", "123456", "123456", "123456", "个人介绍");
    }


}

2.1.8 自动化测试视频

宣纸阁自动化测试

四、 附件

宣纸阁接口测试报告

摘要:
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月临水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值