【测试项目】——个人博客系统自动化测试

news2024/11/15 19:59:22

📖 前言:本文针对个人博客项目进行测试,个人博客主要由四个页面构成:登录页、列表页、详情页和编辑页,主要功能包括:登录、编辑并发布博客、查看详情、删除博客以及注销等功能。对于个人博客的测试就是针对主要功能进行测试,然后按照页面书写测试类。


目录

  • 🕒 1. 博客系统页面概览
  • 🕒 2. 实施流程
  • 🕒 3. 编写思路
    • 🕘 3.1 添加相关依赖
    • 🕘 3.2 包结构
  • 🕒 4. 代码编写
    • 🕘 4.1 公共类AutoTestUtils
    • 🕘 4.2 BlogLoginTest(登录页测试)
    • 🕘 4.3 BlogListTest(列表页测试)
    • 🕘 4.4 BlogEditTest(编辑页测试)
    • 🕘 4.5 BlogDetailTest(详情页测试)
    • 🕘 4.6 BlogDeleteTest(博客删除测试)
    • 🕘 4.7 BlogLogoutTest
    • 🕘 4.8 runSuite(测试套件)
  • 🕒 5. 测试结果
  • 🕒 6. 小结

🕒 1. 博客系统页面概览

登录页:

在这里插入图片描述

列表页:

在这里插入图片描述

详情页:

在这里插入图片描述

编辑页:

在这里插入图片描述

🕒 2. 实施流程

自动化项目实施的基本流程:

  1. 熟悉项目
  2. 设计手工测试用例
  3. 手工测试用例转换成自动化测试用例
  4. 部署

请添加图片描述

🕒 3. 编写思路

  • 依据思维导图编写测试用例:为每个页面创建一个测试类,并在各个测试类中编写测试用例。
  • 公共属性应单独归类以便代码复用。
  • 运用测试套件以简化运行和修改过程。
  • 由于启动和现场截图功能会被频繁复用,应单独建立一个类来存放这些功能。
  • 添加隐式等待以确保页面能正确完全地加载。

🕘 3.1 添加相关依赖

创建Maven空项目后,在pom.xml里添加需要的依赖

<dependencies>
    <!--   添加selenium依赖  -->
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>4.24.0</version>
    </dependency>

    <!--   保存屏幕截图需要用到的包  -->
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.16.1</version>
    </dependency>

    <!--   添加junit5依赖  -->
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.10.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-params</artifactId>
        <version>5.10.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite -->
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-suite</artifactId>
        <version>1.11.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.10.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

🕘 3.2 包结构

在这里插入图片描述

🕒 4. 代码编写

🕘 4.1 公共类AutoTestUtils

功能:创建驱动、保存现场截图

注意:在保存现场截图时,应按日期对文件夹进行分类,并确保图片名称反映出测试类别的名称,以便于问题追踪。同时,要留意文件名的动态生成和时间格式的设定。

public class AutoTestUtils {
    public static WebDriver webDriver;

    @BeforeAll
    static void SetUp() {
        if(webDriver == null)
        {
            webDriver = new ChromeDriver();
        }
        // 设置隐式等待时间为3秒
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    }


    public static void TearDown() {
        webDriver.quit();
    }

    // 保存截图的方法
    public static void saveScreenshot(String testName) {
        // 获取当前时间并格式化
        String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmssSSS").format(new Date());
        String dateFolder = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String fileName = String.format("%s-%s.png", testName, timestamp);

        // 创建文件夹
        File folder = new File("screenshots/" + dateFolder);
        if (!folder.exists()) {
            folder.mkdirs(); // 创建文件夹
        }

        // 保存截图
        File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
        try {
            Files.copy(screenshot.toPath(), Paths.get(folder.getPath(), fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

🕘 4.2 BlogLoginTest(登录页测试)

  1. 创建驱动并打开网页。
  2. 检查网页是否正常加载。
  3. 进行正常登录测试:多参数测试,使用Enter键登录。
  4. 进行异常登录测试:用户名或密码错误,以及为空的情况。
  5. 使用Order注解确保测试按正确顺序执行,避免因顺序错误导致测试失败。
  6. 确保在重新输入用户名和密码前清空之前的内容。
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)

public class BlogLoginTest extends AutoTestUtils {
    // 所有用例都需要先获取登录页面
    @BeforeAll
    static void baseControl() {
        webDriver.get("http://localhost:8080/blog_system/login.html");
    }

    /**
     * 检查登录页面是否正确
     * 右上角与左上角的显示、登录框等
     */

    @Test
    @Order(1)
    void loginPageLoadRight() throws IOException {
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)"));
        webDriver.findElement(By.xpath("/html/body/div[1]/a[2]"));
        webDriver.findElement(By.cssSelector("body > div.login-container > form > div"));
        saveScreenshot(getClass().getName());
    }

    /**
     * 检查登录正常情况:使用多参数测试
     */

    @Order(3)
    @ParameterizedTest
    @CsvFileSource(resources = "LoginSuccess.csv")
    void loginSuccess(String username, String password, String blog_list_url) throws IOException {
        // 在每次登录之后都要进行清空,然后才能重新输入
        webDriver.findElement(By.cssSelector("#username")).clear();
        webDriver.findElement(By.cssSelector("#password")).clear();

        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        webDriver.findElement(By.cssSelector("#login-button")).sendKeys(Keys.ENTER);
        saveScreenshot(getClass().getName());
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 以上是登录步骤,但是并不能确保就是登录成功的
        // 获取到当前页面的URL,如果URL匹配则测试通过
        String cur_url = webDriver.getCurrentUrl();
        Assertions.assertEquals(blog_list_url, cur_url);

        // 列表页展示的用户信息是否是登录账号
        String cur_usr = webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3")).getText();
        Assertions.assertEquals(username, cur_usr);
        // 因为要多参数,所以在执行完一遍执行下一遍的时候需要进行页面的回退,否则找不到登录框
        webDriver.navigate().back();
    }

    /**
     * 测试完成后登录以便进行下一阶段测试
     */

    @Order(4)
    @Test
    void loginSuccessAfter()  {
        webDriver.findElement(By.cssSelector("#login-button")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    }

    /**
     * 检查登录异常情况:使用多参数测试
     */

    @Order(2)
    @ParameterizedTest
    @CsvSource({"admin,123", "lisi,12", "'',''"})       // 第三项为空情况
    void loginFail(String username, String password) throws IOException {
        // 在每次登录之后都要进行清空,然后才能重新输入
        webDriver.findElement(By.cssSelector("#username")).clear();
        webDriver.findElement(By.cssSelector("#password")).clear();

        webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
        webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        webDriver.findElement(By.cssSelector("#login-button")).click();
        saveScreenshot(getClass().getName());
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        // 登录失败的检测,获取文本进行比对
        String expectNotNull = "为空"; // 为空字样
        String expectError = "错误"; // 错误字样
        String actual = webDriver.findElement(By.cssSelector("body")).getText();

        if (actual.contains(expectNotNull) ||  actual.contains(expectError)) {
            System.out.println("登录失败测试通过");
        } else {
            System.out.println("登录失败测试不通过");
        }

        // 导航回登录页
        webDriver.navigate().back();
    }
}

🕘 4.3 BlogListTest(列表页测试)

  1. 检验博客列表页面是否能够正常打开。
  2. 验证列表页面的“查看全文”按钮是否能正确跳转。
  3. 检查未登录时的直接链接是否会重定向到登录页面。
public class BlogListTest extends AutoTestUtils {

    @BeforeAll
    static void baseControl()  {
        webDriver.get("http://localhost:8080/blog_system/blog_list.html");
    }

    /*
     * 博客列表页可以正常显示
     */
    @Test
    void listPageLoadRight() throws IOException {
        // 可以多检查几个,确保正确
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)"));
        webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > img"));
        // 获取页面上所有博客标题对应的元素
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        int title_num = webDriver.findElements(By.cssSelector(".title")).size();
        // 如果元素数量不为0,则测试通过
        Assertions.assertNotEquals(0,title_num);
        saveScreenshot(getClass().getName());
    }
}

🕘 4.4 BlogEditTest(编辑页测试)

  1. 检验编辑页面是否能正确打开
  2. 检查博客发布是否正常:元素是否完整或部分缺失
  3. 验证“写博客”按钮的功能性
public class BlogEditTest extends AutoTestUtils {
    @BeforeAll
    static void baseControl()  {
        webDriver.get("http://localhost:8080/blog_system/blog_list.html");
    }

    /*
     * 博客编辑页可以正常显示
     */

    @Test
    @Order(1)
    void editPageLoadRight() throws IOException {
        // 找到写博客按钮,点击
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 可以多检查几个,确保正确
        webDriver.findElement(By.cssSelector("#submit"));
        webDriver.findElement(By.cssSelector("#blog-title"));
        saveScreenshot(getClass().getName());
    }

    /*
     * 正确编辑并发布博客测试
     */

    @Test
    @Order(2)
    void editAndSubmitBlog() throws IOException {
        // 通过JS输入标题
        ((JavascriptExecutor) webDriver).executeScript("document.getElementById(\"blog-title\").value=\"自动化测试\"");
        // 编辑页的md是第三方插件,所以不可以直接使用sendKeys向编辑模块写入内容,但是可以通过点击上方按钮进行内容的插入
        webDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(30) > a > i")).click();
        webDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(5) > a > i")).click();
        saveScreenshot(getClass().getName());
        // 点击发布
        webDriver.findElement(By.cssSelector("#submit")).click();
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 获取当前页面的URL
        String cur_url = webDriver.getCurrentUrl();
        Assertions.assertEquals("http://localhost:8080/blog_system/blog_list.html", cur_url);
        saveScreenshot(getClass().getName());
    }
}

🕘 4.5 BlogDetailTest(详情页测试)

  1. 正确打开测试详情页:分别测试有blogId和无blogId的情况
  2. 测试删除按钮是否可用,应比较时间而非标题,因为标题可能为空
  3. 注意操作时要确保能够导航回列表页
public class BlogDetailTest extends AutoTestUtils {
    @BeforeAll
    static void baseControl()  {
        webDriver.get("http://localhost:8080/blog_system/blog_list.html");
    }

    public static Stream<Arguments> Generator() {
        return Stream.of(Arguments.arguments("http://localhost:8080/blog_system/blog_detail.html",
                "博客详情页","自动化测试"));
    }

    @ParameterizedTest
    @MethodSource("Generator")
    void BlogDetail(String expected_url,String expected_title,String expected_blog_title) {
        // 找到第一个博客对应的查看全文按钮
        webDriver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/a")).click();
        // 获取当前页面的URL、页面title、博客标题
        String cur_url = webDriver.getCurrentUrl();
        String cur_title = webDriver.getTitle();
        String cur_blog_title = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div > h3")).getText();
        Assertions.assertEquals(expected_title, cur_title);
        Assertions.assertEquals(expected_blog_title, cur_blog_title);
        if (cur_url.contains(expected_url)) {
            System.out.println("测试通过");
        } else {
            System.out.println("测试不通过");
        }
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        saveScreenshot(getClass().getName());
    }
}

🕘 4.6 BlogDeleteTest(博客删除测试)

  1. 测试博客是否真正删除了
  2. 尝试删除别人的文章
  3. 删除完返回列表页
public class BlogDeleteTest extends AutoTestUtils {
    @BeforeAll
    static void baseControl()  {
        webDriver.get("http://localhost:8080/blog_system/blog_list.html");
    }

    @Test
    void DeleteBlog () {
        // 点击查看全文按钮
        webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();
        // 点击删除按钮
        webDriver.findElement(By.cssSelector("#delete_button")).click();
        // 博客列表页第一篇博客不是“自动化测试”
        String first_blog_title = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();
        // 校验当前博客标题不等于“自动化测试”
        Assertions.assertNotEquals(first_blog_title,"自动化测试");
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        saveScreenshot(getClass().getName());

        // 尝试删除别人的文章
        // 点击查看全文按钮
        webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();
        // 点击删除按钮
        webDriver.findElement(By.cssSelector("#delete_button")).click();
        // 删除失败的检测,获取文本进行比对
        String expectError = "没有权限"; // 没有权限错误字样
        String actual = webDriver.findElement(By.cssSelector("body")).getText();

        if (actual.contains(expectError)) {
            System.out.println("删除失败测试通过");
        } else {
            System.out.println("删除失败测试不通过");
        }
        saveScreenshot(getClass().getName());
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        // 导航回列表页
        webDriver.navigate().back();
    }
}

🕘 4.7 BlogLogoutTest

  1. 测试注销后是否返回登录页
  2. 断开驱动连接
public class BlogLogoutTest extends AutoTestUtils {
    @BeforeAll
    static void baseControl()  {
        webDriver.get("http://localhost:8080/blog_system/blog_list.html");
    }

    @Test
    void Logout(){
        webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)")).click();
        // 校验当前页面URL是否是“http://localhost:8080/blog_system/login.html”
        String cur_url=webDriver.getCurrentUrl();
        Assertions.assertEquals("http://localhost:8080/blog_system/login.html",cur_url);
        // 校验提交按钮
        WebElement webElement = webDriver.findElement(By.cssSelector("#login-button"));
        Assertions.assertNotNull(webElement);
        webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        saveScreenshot(getClass().getName());
        //webDriver.quit();
        TearDown();
    }
}

🕘 4.8 runSuite(测试套件)

测试套件按照测试类的顺序执行。

@Suite
@SelectClasses({BlogLoginTest.class, BlogListTest.class, BlogEditTest.class, BlogInfoChecked.class, BlogDetailTest.class, BlogDeleteTest.class, BlogLogoutTest.class})
public class runSuite {
}

🔎 自动化测试完整源码+博客项目

🕒 5. 测试结果

实际效果(无倍速):
请添加图片描述

在这里插入图片描述

🕒 6. 小结

  1. 关注测试用例的执行顺序
  2. 检查页面元素是否存在,以确保正确性。
  3. 注意多参数测试中的页面导航问题。
  4. 多参数(多用户登录)可能导致高并发服务器错误,需交由开发处理。
  5. 登录页面测试的最后一步应为登录成功状态,以便后续测试顺利进行。
  6. 驱动关闭应在最后一个用例结束后进行。
  7. 在公共类中定义保存截图方法以保存所有用例的执行结果,便于后续查错。截图保存时使用动态时间戳,按照天或周分类保存。
  8. @SelectClasses可指定执行类的顺序。
  9. 建议获取固定元素(如时间、标题)时,使用 XPath 定位。因为 XPath 可以基于元素的层级关系和属性进行查找,所以它适合用于固定元素的定位,特别是在复杂的 DOM 结构中。
  10. 可以适当关注用例执行时间,排查是否为性能问题。
  11. 可创建单独类存放驱动释放方法,放在套件测试的最后。
  12. 测试用例数量并非越多越好。
  13. 可以使用无头模式创建驱动。

【面试题】使用Selenium 4 自动化测试工具和JUnit 5 单元测试框架结合,如何实现的,以及有什么亮点?

1)实施:
① 设计测试用例是基于个人项目的需求,通过结合Selenium 4自动化测试工具和JUnit 5单元测试框架来执行Web自动化测试(功能、步骤和技术必须明确)。
② 需要对代码中的每个包提供概要介绍(公共属性[可复用]、测试用例[基于每个页面设计]),并使用测试套件来加载所有测试类。

2)特点:
① 利用JUnit 5提供的注解,避免创建过多对象,节省资源和时间,提升自动化测试的执行效率。
只创建一次驱动对象,减少每个测试用例重复创建驱动对象,节约时间和资源。
③ 采用参数化测试,使测试用例保持简洁,提高代码可读性。
④ 通过测试套件,减少了测试人员的工作量,一次性执行所有测试用例。
⑤ 使用隐式等待机制,确保页面加载完成,提升了自动化测试的运行效率和稳定性,减少了误报的可能性。
⑥ 采用屏幕截图功能,便于问题追踪和解决。
⑦ 使用无头模式,专注于测试结果,节省屏幕空间。

编写自动化测试不难,但要提高执行速度、更有效地发现问题并避免误报才是挑战。


OK,以上就是本期知识点“个人博客系统测试”的知识啦~~ ,感谢友友们的阅读。后续还会继续更新,欢迎持续关注哟📌~
💫如果有错误❌,欢迎批评指正呀👀~让我们一起相互进步🚀
🎉如果觉得收获满满,可以点点赞👍支持一下哟~

❗ 转载请注明出处
作者:HinsCoder
博客链接:🔎 作者博客主页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2165195.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript的注释与常见输出方式

注释 源码中注释是不被引擎所解释的&#xff0c;它的作用是对代码进行解释。Javascript 提供两种注释的写法:一种是单行注释&#xff0c;用//起头;另一种是多行注释&#xff0c;放在/*和*/之间。 单行注释&#xff1a; //这是单行注释 多行注释&#xff1a; /*这是 多行 注…

享元模式详解:内存优化的利器

享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享相同对象来减少内存消耗&#xff0c;从而提高系统性能。享元模式适用于大量细粒度对象的场景&#xff0c;这些对象具有相同或相似的状态。 一&#xff0c;享元模式的结构 享元模…

NXP i.MX8系列平台开发讲解 - 4.1.5 GNSS篇(五) - GPSD 编译(包含交叉编译)详解

专栏文章目录传送门&#xff1a;返回专栏目录 Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 文章目录 目录 1. 编译GPSD[Ubuntu] 2. 交叉编译 2.1 解决依赖库编译 2.1.1 libusb 编译 2.1.2 libncurses 编译…

Redis的一些通用指令

首先我们需要先连接客户端服务器&#xff0c;此时我们需要通过redis-cli和redis服务器进行交互&#xff0c;输入ping来确保通路的流畅 &#xff08;一&#xff09;get和set redis中最核心的两个命令就是get和set&#xff0c;get就是根据key来取出对应value&#xff0c;set就是把…

2024年汉字小达人区级自由报名比赛的真实流程图解——和往年比有一个重大变化

今天是2024年9月25日&#xff0c;上海小学生&#xff08;和家长&#xff09;们最关注的赛事之一——美丽汉字中文自修杯第十一届上海市小学生汉字小达人区级自由报名区级比赛正式开始了&#xff01; 虽然今天才是比赛的第一天&#xff0c;但是很多孩子已经摩拳擦掌开始展示自己…

信息安全工程师(18)常见密码算法

前言 常见的密码算法主要分为三大类&#xff1a;对称加密算法、非对称加密算法和摘要算法。 一、对称加密算法 对称加密算法&#xff0c;又称为秘密密钥算法或单密钥算法&#xff0c;是指加密和解密使用相同密钥的加密方式。这种算法的特点是加密速度快&#xff0c;适用于大量数…

【延时队列的实现方式】

文章目录 延时队列JDK自带的延时队列实现Redis实现延迟队列RabbitMQ 延时队列 延时队列 延时队列是一种特殊类型的队列&#xff0c;它允许元素在特定时间间隔后才能被处理。这种队列在处理具有延迟需求的任务时非常有用&#xff0c;例如定时任务、事件驱动系统等 延时队列在项…

Cannon-es.js编程进阶:复杂形状的碰撞

本文目录 前言最终复杂模型碰撞效果1、碰撞事件及休眠事件1.1 前文回顾及代码整改1.2 效果1.3 监听碰撞事件与休眠1.3.1 碰撞事件collide1.3.2 休眠事件sleepy及sleep2、多个形状的组合物体碰撞2.1 效果3、Trimesh3.1 代码3.2 效果前言 我们在Cannon-es.js基础入门:3D 物理碰撞…

新闻媒体宣发套餐扩大影响力和建立品牌形象方法-华媒舍

在当今互联网时代&#xff0c;营销推广是任何企业必须要面对的挑战。而在众多的营销方式中&#xff0c;精准投放和新闻媒体宣发套餐推广成为了越来越受欢迎的选择。本文将从精准投放和新闻媒体宣发套餐推广两个方面进行科普介绍&#xff0c;解析其背后的重要意义和带来的百倍回…

微软宣布弃用WSUS,企业用户尽早准备替换方案

微软最近宣布将逐步弃用Windows Server Update Services (WSUS)&#xff0c;不再为其开发新功能&#xff0c;但会继续支持现有的更新和功能。这一决定对企业客户来说影响深远&#xff0c;尤其是那些依赖WSUS来管理大规模Windows设备更新的组织。 对企业客户的影响 安全性与合规…

如何使用ant design vue的a-select下拉框,实现既能输入内容,也可以下拉选择的效果,apiselect同样适用

修改mode 强烈推荐 代码如下&#xff0c;重点在search和mode <ApiSelectv-if"editableData[record.key]"mode"SECRET_COMBOBOX_MODE_DO_NOT_USE"search"inputinspect":api"problem":params"{projectId:projectId}"showS…

[前端]DOM+CSS+HTML实现水波进度效果

效果展示&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Documen…

PAT甲级-1115 Counting Nodes in a Binary Search Tree

题目 题目大意 给定节点个数&#xff0c;以及每个节点的值&#xff0c;要求构造一棵二叉排序&#xff08;搜索&#xff09;树&#xff0c;并按照规定格式输出最后一层和倒数第二层的节点个数。 思路 二叉排序树的构造方法是递归&#xff0c;但思路类似于二分查找。逐个将n个…

浅克隆与深克隆

1、浅克隆 1.1、什么是浅克隆&#xff1f; 被复制对象的所有变量都含有与原来的对象相同的值&#xff0c;而所有的对其他对象的引用仍然 指向原来的对象(克隆对象与原型对象共享引用数据类型变量)。 如下图所示&#xff1a; 1.2、浅克隆代码实现 类实现接口 Cloneable&#xf…

教育在线答题在线小程序源码系统 PHP+MySQL组合开发源码开源可二次开发 带搭建部署教程

系统概述 教育在线答题在线小程序源码系统是一款专为教育行业设计的&#xff0c;集在线题库管理、智能组卷、在线答题、自动评分、成绩分析等功能于一体的综合性平台。该系统采用PHP作为后端开发语言&#xff0c;结合MySQL数据库进行数据存储与管理&#xff0c;确保了系统的稳…

数据在内存中的存储(下)

目录 前言一、浮点数在内存中的存储1.1 练习1.2 浮点数的存储1.2.1 浮点数存的过程1.2.2 浮点数取的过程 1.3 题目解析 总结 前言 前面一期我们主要说到整形在数据中的存储方式&#xff0c;这期我们来看看浮点数在内存中是如何存储的&#xff0c;话不多说&#xff0c;正文开始…

Proto3 深度解读:Protobuf 的用法与实例分析(C++)

文章目录 1. 前言1.1 序列化和反序列化1.2 什么情况下要进行序列化1.3 部分序列化工具 2. 了解Protobuf2.1 什么是Protobuf2.2 proto 成分2.3 如何编译proto2.4 编译.proto文件后生成的文件都有什么&#xff1f; 3. Protobuf的使用3.1 Protobuf的使用过程3.2 上手编写实例 4. p…

打印沙漏(最蠢的办法)

直接给代码&#xff0c;很好理解的 #include<bits/stdc.h> using namespace std; int s(int b){if(b<1)return 0;if(b2)return 1;for(int i3;i<sqrt(b);i){if(b%i0)return 0;}return 1; } int main(){int n;cin>>n;char c;cin>>c;vector<int>s;…

什么是服务器日志,日志有什么作用?

前言 服务器日志是指服务器等电脑设备或软件的运作记录‌。这些日志记录了服务器接收客户端处理请求的过程以及服务器对这些请求的处理结果。服务器日志对于排查和解决计算机系统和网络应用中的问题至关重要&#xff0c;因为它们包含了用于调试问题的消息、服务器状态以及其他…

深入解析网络通信关键要素:IP 协议、DNS 及相关技术

我的主页&#xff1a;2的n次方_ 1. IP 协议报头结构 4 位版本&#xff1a;表示 IPv4 / IPv6 4 位首部长度&#xff1a;表示 IP 报头的长度&#xff0c;以 4 字节为单位 8 位服务类型&#xff1a;包括 3 位优先权字段&#xff08;已弃用&#xff09;&#xff0c;4 位 TOS 字…