【测试开发】第六节.测试——对个人博客系统进行web自动化测试(包含测试代码和测试的详细过程)

作者简介:大家好,我是未央;

博客首页:未央.303

系列专栏:Java测试开发

每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!

文章目录

  • 前言
  • 一、项目总述
  • 二、登录页面测试
  •       2.1 准备工作
  •       2.2 验证页面显示是否正确
  •       2.3 验证正常登录的情况
  •       2.4 验证登录失败的情况
  •       2.5 关于登录界面的总代码
  •       2.6 测试视频
  • 三、注册界面的自动化测试
  •       3.1 测试代码
  •       3.2 测试过程中的BUG
  •       3.3 测试视频
  • 四、博客列表页测试
  •       4.1 用户已登录情况下的测试
  •       4.2 用户未登录情况下的测试
  • 五、博客详情页测试
  •       5.1 用户已登录情况下的测试
  •       5.2 用户未登录情况下的测试
  • 六、个人主页测试
  • 七、博客编辑页面测试
  •       7.1 用户登录的情况下
  • 八、博客修改页面测试
  •       8.1 用户登录的情况下
  • 九、总结
  •       9.1 总测试视频
  •       9.2 总代码
  • 总结


前言


一、项目总述

还记得这个SpringBoot实战项目吗?

今天我们就对这个web项目,用selenium进行自动化测试,看看这个项目有什么问题?

是否达到了我们的预期效果。

首先要对这个博客各个页面设计测试页面。

下面我们就一个页面一个页面的写代码,进行测试。


二、登录页面测试

2.1 准备工作

1.首先我们新建一个Maven项目。


2.在 test包下面写我们的测试代码。

因为我们在自动化测试的时候要频繁获取页面中的元素,但很多时候我们页面元素的加载速度赶不上我们自动化代码的执行速度,所以就会导致找不到元素这种情况。

可以看到,报了错误——》找不到我们页面对应的元素。


3.那么我们加上隐式等待试试


因此,我们不如在整个项目中,创建一个公共类

(进行隐式等待,让我们的程序能够等一下我们的页面加载)

【 隐式等待 作用于 WebDriver 整个生命周期】

【只要没有走到 driver.quit,即没有退出浏览器,隐式等待都是一直存在的】 

所以我们之后要写的登录界面只要继承的隐式等待,

自然也能够使得测试登录界面的代码能够稍微停顿一下,等页面渲染完成。


下面我们进行登录页面的自动化测试代码编写

我们要编写3个测试用例

  • 验证页面显示是否正确
  • 验证正常登录的情况
  • 验证登录失败的情况

首先因为我们每个测试用例都要 创建驱动实例,进入到用户登录页面、所以我们不妨这样做:

这样再将我们的测试用例按一定的顺序来执行,就会使得我们的整个测试过程很流程、自然。


2.2 验证页面显示是否正确

代码示例:

/**
     * 检查登录页面是否正常显示
     * @throws InterruptedException
     */
    @Test  
    @Order(1)
    void loginPageTest() throws InterruptedException {
        // 隐式等待--// 隐式等待,更加丝滑——》作用于下面的整个作用领域,这个方法中的所有元素,在这3秒内不断轮询
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
        // 利用断言判断登录的文本内容显示是否正确
        String expect = "登录";
        String actual = driver.findElement(By.cssSelector("body > div.login-container > div > h3")).getText(); // 检查登录页面的登录文本是否存在
        Assertions.assertEquals(expect, actual);
 
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)")); // 检查博客登录页的主页超链接是否存在
        // 检查提交按钮是否存在
        driver.findElement(By.cssSelector("#submit"));
 
    }

 上面中我们用到了junit和隐式等待:


junit 中提供和了非常强大的注解功能
@Test说明方法 是测试方法,执行当前这个类时,会自动的执行该类下的所有带@Test注解的用例


测试示例:

下面我们进行测试


2.3 验证正常登录的情况

代码示例:

/**
     * 检查正常登录的情况,每写一个测试用例就测试一下
     */
    @ParameterizedTest // 写了该注解就不用在写@Test注解了(多参数)
    @Order(2)
    @CsvSource({"admin, admin", "小鱼儿, 123"})
    void loginRightTest(String username, String password) throws InterruptedException, IOException {
        // 隐式等待是作用不了非HTML页面的元素的,所以弹窗无法等待,看下是否在切换到弹窗之前弹窗还没有出现,终端报的错误是不是noalert
        // 多个账号登录,在重新输入账号时,需要把之前的输入的内容清空
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        // 隐式等待无法处理弹窗 && 显示等待和隐式等待无法共存(父类AutotestUtils中用了隐式等待)
        Thread.sleep(100); // 显示等待,等待弹窗出现
        Alert alert = driver.switchTo().alert();
        alert.accept(); // 选择确认
 
        // 上述步骤只是说明输入了账号和密码,但还不知道点击提交后是否会跳转到博客列表页
        String expect = "http://49.235.66.46:9000/blog_list.html";
        String actual = driver.getCurrentUrl();
        Assertions.assertEquals(expect, actual); // 查看当前的url是否在博客详情页面
        // 进行截图,看当前是否跳转到了登录界面
        // 程序执行的速度和页面渲染的速度
        File srcFile =  driver.getScreenshotAs(OutputType.FILE);
        String fileName = "loginRightTest.png";
        FileUtils.copyFile(srcFile, new File(fileName));
        //因为我们要测试多个账号,所有在一个账号检测完了后,还需要回退到登录界面
        driver.navigate().back();
    }

测试示例:


该过程中出现的问题

在验证用户正常登录的过程中,我一开始没有用强制等待或者显示等待(我只是用了隐式等待)。结果——在处理弹窗的过程就出现了问题。

解答:

 咦!不对呀,我不是用了隐式等待了吗?

难道不应该是等弹窗加载完了,程序才会继续往下执行——获取弹窗的吗?

原来:

隐式等待是作用不了非HTML页面的元素的,所以弹窗无法等待(弹窗还没有出现,页面还没加载完成,我们的程序就在尝试着获取弹窗了——》这怎么获取?自然就报错了!!!


那么我们既然用不了隐式等待,我们用显示等待好了。

但你别忘了,你这个对登录界面测试的类是继承了AutoTestUtils的(里面实现了隐式等待)


并且——显示等待和隐式等待尽量不要共存(会出现一些意想不到的错误)

所以呢?这种情况下,我们只好用强制等待了。

但是——强制等待是比较消耗时间的 

我们需要考虑在整个项目中,类似这样的强制等待多不多,如果太多的话——我们就要考虑重写换一种策略了。


2.4 验证登录失败的情况

代码示例:

    /**
     * 检查登录失败的情况
     */
    @Order(3)
    @ParameterizedTest // 多个参数
    @CsvSource({"admin, 123"})
    void loginFailTest(String username, String password) throws IOException, InterruptedException {
        // 把之前默认填充内容清空
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(100);
        Alert alert = driver.switchTo().alert();
        System.out.println(alert.getText());
    }

测试示例:


2.5 关于登录界面的总代码

登录界面总代码:

package webAutoTest.tests;
 
import com.sun.xml.internal.stream.StaxErrorReporter;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import webAutoTest.common.AutotestUtils;
import org.openqa.selenium.OutputType;
 
import java.io.File;
import java.io.IOException;
import java.time.Duration;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 说明当前该类下面的测试方法要按一定的顺序执行
public class loginTest extends AutotestUtils {
    public static ChromeDriver driver = createDriver();
    @Test
    @BeforeAll // 被@BeforeAll修饰的方法要是静态的
    static void init() {
        // 跳转到博客登录页面
        driver.get("http://49.235.66.46:9000/login.html");
    }
 
    /**
     * 检查登录页面是否正常显示
     * @throws InterruptedException
     */
    @Test
    @Order(1)
    void loginPageTest() throws InterruptedException {
        // 隐式等待--// 隐式等待,更加丝滑——》作用于下面的整个作用领域,这个方法中的所有元素,在这3秒内不断轮询
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
        // 利用断言判断登录的文本内容显示是否正确
        String expect = "登录";
        String actual = driver.findElement(By.cssSelector("body > div.login-container > div > h3")).getText(); // 检查登录页面的登录文本是否存在
        Assertions.assertEquals(expect, actual);
 
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)")); // 检查博客登录页的主页超链接是否存在
        // 检查提交按钮是否存在
        driver.findElement(By.cssSelector("#submit"));
 
    }
 
    /**
     * 检查正常登录的情况,每写一个测试用例就测试一下
     */
    @ParameterizedTest // 写了该注解就不用在写@Test注解了(多参数)
    @Order(2)
    @CsvSource({"admin, admin", "小鱼儿, 123"})
    void loginRightTest(String username, String password) throws InterruptedException, IOException {
        // 多个账号登录,在重新输入账号时,需要把之前的输入的内容清空
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(100);
        Alert alert = driver.switchTo().alert();
        alert.accept(); // 选择确认
 
        // 上述步骤只是说明输入了账号和密码,但还不知道点击提交后是否会跳转到博客列表页
        String expect = "http://49.235.66.46:9000/blog_list.html";
        String actual = driver.getCurrentUrl();
        Assertions.assertEquals(expect, actual); // 查看当前的url是否在博客详情页面
        // 进行截图,看当前是否跳转到了登录界面
        // 程序执行的速度和页面渲染的速度
        File srcFile =  driver.getScreenshotAs(OutputType.FILE);
        String fileName = "loginRightTest.png";
        FileUtils.copyFile(srcFile, new File(fileName));
        //因为我们要测试多个账号,所有在一个账号检测完了后,还需要回退到登录界面
        driver.navigate().back();
    }
 
    /**
     * 检查登录失败的情况
     */
    @Order(3)
    @ParameterizedTest // 多个参数
    @CsvSource({"admin, 123"})
    void loginFailTest(String username, String password) throws IOException, InterruptedException {
        // 把之前默认填充内容清空
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password")).clear();
        driver.findElement(By.cssSelector("#username")).sendKeys(username);
        driver.findElement(By.cssSelector("#password")).sendKeys(password);
        driver.findElement(By.cssSelector("#submit")).click();
        Thread.sleep(100);
        Alert alert = driver.switchTo().alert();
        System.out.println(alert.getText());
    }
    @AfterAll
    @Test
    static void quit() {
        driver.quit();
    }
}

2.6 测试视频


三、注册界面的自动化测试

3.1 测试代码

package webAutoTest.tests;
 
import org.apache.commons.io.FileUtils;
import org.checkerframework.checker.units.qual.A;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.chrome.ChromeDriver;
import webAutoTest.common.AutotestUtils;
 
import java.io.File;
import java.io.IOException;
 
/**
 * 注册界面的自动化测试
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 说明当前该类下面的测试方法要按一定的顺序执行
public class regTest extends AutotestUtils { // 继承用于隐式等待的公共方法
    public static ChromeDriver driver = new ChromeDriver();
    @Test      // @Test说明方法 是测试方法,执行当前这个类时,会自动的执行该类下的所有带@Test注解的用例
    @BeforeAll // 带有BeforeAll注解的方法会在当前类下的所有测试用例之前(方法)执行一次,注意只是执行一次
    public static void init() {
        // 既然是对注册界面的测试,自然要先跳转到该界面
        driver.get("http://49.235.66.46:9000/reg.html");
    }
 
    /**
     * 对页面内容的完整性进行测试
     */
    @Test
    @Order(1)
    public void regPageTest() {
        // 利用断言验证页面显示的文本是否正确
        String expect = "注册";
        String actual = driver.findElement(By.cssSelector("body > div.login-container > div > h3")).getText();
        Assertions.assertEquals(expect, actual); // 如果不正确
 
        driver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)")); // 检查博客登录页的主页超链接是否存在
        // 检查提交按钮是否存在
        driver.findElement(By.cssSelector("#submit"));
    }
    /**
     * 正常注册
     */
    @ParameterizedTest // 多参数——加了该注解就不用@Test了
    @Order(2)
    @CsvSource({"皮皮, 123456, 123456"}) // 多参数
    public void regRightTest(String username, String password1, String password2) throws InterruptedException, IOException {
        // 每次都要提前把之前输入框的内容给清除(不管有没有内容)
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password1")).clear();
        driver.findElement(By.cssSelector("#password2")).clear();
        // 将信息填入输入框
        driver.findElement(By.cssSelector("#username")).sendKeys(username);
        driver.findElement(By.cssSelector("#password1")).sendKeys(password1);
        driver.findElement(By.cssSelector("#password2")).sendKeys(password2);
        // 找到提交按钮,并点击提交
        driver.findElement(By.cssSelector("#submit")).click();
        // 强制等待,让弹窗显示出来(避免我们页面还没加载完成,我们下面的代码就尝试获取弹窗
        Thread.sleep(500);
 
        // 注册成功后,会出现弹窗,获取弹窗并且关闭
        Alert alert = driver.switchTo().alert();
        alert.accept(); // 点击弹窗中的确定,以便让程序继续执行下去
        // 注册成功后,应该会跳转到登录页面
        Thread.sleep(100);
        String expectURL = "http://49.235.66.46:9000/login.html";
        String actualURL = driver.getCurrentUrl(); // 获取当前页面的URL
        Assertions.assertEquals(expectURL, actualURL);
        // 获取此时的屏幕截图,此时应该以及跳转到了登录页面
        File srcFile = driver.getScreenshotAs(OutputType.FILE);
        String fileName = "regRightTest.png";
        FileUtils.copyFile(srcFile, new File(fileName));
        // 因为注册成功会跳转到登录界面,所以但接下来我们还有在注册界面测试,所以要回退到注册界面
        driver.navigate().back();
    }
    /**
     * 测试注册失败的情况
     * (小鱼儿这个用户名我以及注册过了再次注册,由于用户名的唯一约束,会导致注册失败)
     * (前后两次输入的密码不一致)
     */
    @ParameterizedTest
    @Order(3)
    @CsvSource({"小鱼儿, 1234, 1234", "阿良, 123, 123456"})
    public void regFailTest(String username, String password1, String password2) throws InterruptedException {
        // 每次输入信息前, 先要清除输入框的原有内容
        driver.findElement(By.cssSelector("#username")).clear();
        driver.findElement(By.cssSelector("#password1")).clear();
        driver.findElement(By.cssSelector("#password2")).clear();
        // 往输入框中输入数据
        driver.findElement(By.cssSelector("#username")).sendKeys(username);
        driver.findElement(By.cssSelector("#password1")).sendKeys(password1);
        driver.findElement(By.cssSelector("#password2")).sendKeys(password2);
        driver.findElement(By.cssSelector("#submit")).click();
        // 等待弹窗加载完成
        Thread.sleep(100);
        Alert alert = driver.switchTo().alert(); // 获取弹窗
        // 利用断言判断是否注册失败
        if (password1.equals(password2)) {
            String expect = "注册失败,请检查你的输入!"; // 前后密码一致的情况下
            String actual = alert.getText();
            alert.accept(); // 获取到弹窗内容后在关闭弹窗
            Assertions.assertEquals(expect, actual); // 看浏览器的实际弹窗内容是否和我们预期的一样
        }
        else {
            String expect = "两次密码输入不一致,请先检查!";
            String acutal = alert.getText();
            alert.accept();
            Assertions.assertEquals(expect, acutal);
        }
 
    }
 
    /**
     * 关闭注册弹窗
     */
    @Test
    @AfterAll  // 带有AfterAll注解的方法会在当前类下的所有测试用例(方法)执行之后 执行一次,注意只是执行一次
    public static void close() {
        driver.quit();
    }
 
}

3.2 测试过程中的BUG

在注册页面的自动化测试的过程中,我通过多对象传入同一个测试方法来对多种注册失败的情况进行测试(该用户以及注册、前后密码输入不一致)

结果在通过断言——发现我预期的弹窗内容和实际的弹窗内容不一致,导致测试的时候出现问题.


通过查看下面的报错信息,结合程序一起查看,我才发现——我的判断条件有问题

应该用password1.equals(password2)

接着我改好了,但程序又出现了问题🤔

No ParameterResolver registered for parameter [java.lang.String arg1] in method [public void webAutoTest.tests.regTest.regFailTest(java.lang.String,java.lang.String,java.lang.String) throws java.lang.InterruptedException].

中间的逗点我写成了全角的中文——》当然有问题啊

改成半角的逗点后——》又又有新的问题出现了😂

通过这行报错信息可以看出

Command: [f0ef8a1466c85d3fc87f96ebd8e83a28, findElement {using=css selector, value=#username}]

在第二个错误登录的测试用例的执行的时候——》他找不到页面中的元素#username。

不对呀!!!我明明这个cssSelector写的没有问题啊,页面中也确实存在这个元素啊,为什么会找不到呢?

后来我把 ——driver.findElement(By.cssSelector("#username")).clear();

这行代码给注释掉了结果

看来不是页面元素selector的问题,难道是页面加载还没完成???

不会的——我们整个类继承了AutotestUtil(里面实现了隐式等待了啊,这里又不是弹窗,隐式等待应该能够发挥作用的呀!!!)

弹窗——于是我检查了代码中有关弹窗的部分。

结果:


没错,我是获取弹窗了

但是我没关闭弹窗啊!!!

这就导致在执行第二个测试用例的时候,上一个测试用例的弹窗还没有关闭——当然获取不到第二个测试用例的输入了呀!

终于可以了,不容易啊!


3.3 测试视频


四、博客列表页测试

首先对于博客列表页面来说,分为登录情况下的测试和未登录情况下的测试。


4.1 用户已登录情况下的测试

代码示例:

package webAutoTest.logined_tests;
 
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import webAutoTest.common.AutotestUtils;
 
/**
 * 用户登录状态下的博客列表测试
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 说明当前类中的测试方法要按一定的顺序来执行---和order配合使用
public class blogListTest extends AutotestUtils {
    private static ChromeDriver driver = new ChromeDriver();
    @Test
    @BeforeAll
    static void init() {
        driver.get("http://49.235.66.46:9000/blog_list.html");
    }
 
    /**
     * 测试总的博客列表页面的完整性
     */
    @Test
    @Order(1)
    void pageTest() { // 不能用private修饰该方法——》我们的selenium还要调用该方法
        // 看看是否能够获取到博客列表页面的翻页按钮(只有总的博客列表页有,个人主页也没有)
        driver.findElement(By.cssSelector("body > div.container > div > div.blog-pagnation-wrapper > button:nth-child(1)"));
        // 查看页面的文本内容显示是否正确
        String expect = "Linux删除文件操作";
        String actual = driver.findElement(By.cssSelector("body > div.container > div > div:nth-child(2) > div.title")).getText();
        Assertions.assertEquals(expect, actual); // 断言
        // 查看是否有个人主页的超链接
        driver.findElement(By.cssSelector("#myblog")).click();
        String  expectURL = "http://49.235.66.46:9000/myblog_list.html";
        String actualURL = driver.getCurrentUrl();
        // 利用断言看:在登录成功的情况下,界面是否跳转到了个人主页
        Assertions.assertEquals(expectURL, actualURL);
    }
    @Test
    @AfterAll
    static void exit() {
        driver.quit();
    }
 
}

视频演示


4.2 用户未登录情况下的测试

代码示例:
 

package webAutoTest.unlogined_tests;
 
import org.junit.jupiter.api.*;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import webAutoTest.common.AutotestUtils;
 
/**
 * 用户未登录状态下的博客列表测试
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // 说明当前类中的测试方法要按一定的顺序来执行---和order配合使用
public class blogListTest extends AutotestUtils {
    private static ChromeDriver driver = new ChromeDriver();
    @Test
    @BeforeAll
    static void init() {
        driver.get("http://49.235.66.46:9000/blog_list.html");
    }
 
    /**
     * 测试总的博客列表页面的完整性
     */
    @Test
    @Order(1)
    void pageTest() throws InterruptedException { // 不能用private修饰该方法——》我们的selenium还要调用该方法
        // 看看是否能够获取到博客列表页面的翻页按钮(只有总的博客列表页有,个人主页也没有)
        driver.findElement(By.cssSelector("body > div.container > div > div.blog-pagnation-wrapper > button:nth-child(1)"));
        // 查看页面的文本内容显示是否正确
        String expect = "Linux删除文件操作";
        String actual = driver.findElement(By.cssSelector("body > div.container > div > div:nth-child(2) > div.title")).getText();
        Assertions.assertEquals(expect, actual); // 断言
        // 查看是否有个人主页的超链接
        driver.findElement(By.cssSelector("#myblog")).click();
        Thread.sleep(100); // 强制等待弹窗的出现(隐式等待无法处理弹窗/显示等待和隐式等待尽量不共存)
        // 在未登录的情况下,页面跳转到个人主页是否会出现弹窗(以及弹窗内容是否和我们预期的一致)
        Alert alert = driver.switchTo().alert();
        String expectAlert = "当前用户未登录,你即将跳转到登录页面";
        String actualAlert = alert.getText();
        Assertions.assertEquals(expectAlert, actualAlert);
        // 不要忘了关闭弹窗
        alert.accept();
    }
    @Test
    @AfterAll
    static void exit() {
        driver.quit();
    }
 
}

一些问题,在实际测试的时候,我发现当用private修饰测试方法时

这是因为private修改的方法只在当前类中可见,外部类不可见。

但是我们是借助selenium来进行自动化测试,那么这样一来,selenium就调用不了这个测试方法了————》当然也就执行不了测试用例了。


总结

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OAK深度相机主机时钟同步提升10倍!

编辑:OAK中国 首发:oakchina.cn 喜欢的话,请多多👍⭐️✍ 内容可能会不定期更新,官网内容都是最新的,请查看首发地址链接。 ▌前言 Hello,大家好,这里是OAK中国,我是Ash…

Linux, Certbot快速申请免费https证书

linux环境. 更新apt,为了能正确的下载certbot apt update 安装certbot apt install certbot 如果之前nginx已经开启着了,先关掉,防止端口占用 nginx -s stop 运行certbot开始获取证书文件 certbot certonly 输入1直接回车,意思就是让certbot模拟一个web服务器执行下面的…

走进水稻种植教学基地可视化:科技与农业知识的完美结合

随着科技的不断发展,农业领域也在不断创新和进步。水稻种植教学基地可视化系统是一种基于现代信息技术手段的教学方式,通过虚拟现实、3D建模等技术,将水稻种植的全过程进行模拟和展示。这种教学方式打破了传统农业教学的局限性,使…

treeview

QML自定义一个TreeView,使用ListView递归 在 Qt5 的 QtQuick.Controls 2.x 中还没有 TreeView 这个控件(在 Qt6 中出了一个继承自 TableView 的 TreeView),而且 QtQuick.Controls 1.x 中的也需要配合 C model 来自定义&#xff0c…

3d模型上的材质怎么删除---模大狮模型网

在大多数3D软件中,可以通过以下步骤来删除3D模型上的材质: 选择要删除材质的模型:首先,从场景中选择包含目标材质的模型。可以使用选择工具或按名称查找模型。 进入编辑模式:将模型切换到编辑模式。这通常需要选择相应…

力扣(leetcode)第118题杨辉三角(Python)

118.杨辉三角 题目链接:118.杨辉三角 给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] …

MIDI码深度解析

MIDI 协议即数字音乐接口(Musical Instrument Digital Interface),是电子乐器、合成器等演奏设备之间的一种即时通信协议,用于硬件之间的实时演奏数据传递。如果理解还不够深刻,官方如下解释: 常用midi硬件…

超强的AI写简历软件

你们在制作简历时,是不是基本只关注两件事:简历模板,还有基本信息的填写。 当你再次坐下来更新你的简历时,可能会发现自己不自觉地选择了那个“看起来最好看的模板”,填写基本信息,却没有深入思考如何使简历…

15EG使用ps点亮mio的led

创建工程模板在hello_world中已经介绍过了,这里直接从配置完zynq 开始 因为要用到ps的GPIO,所以要对ZYNQ进行额外的配置,双击ZYNQ打开配置->打开IO口配置->勾选GPIO0 MIO外设。我们可以在原理图中看到mio的led引脚为MIO24和MIO25&#…

Django模型(四)

一、数据操作初始化 from django.db import models# Create your models here. class Place(models.Model):"""位置信息"""name = models.CharField(max_length=32,verbose_name=地名)address = models.CharField(max_length=64,null=True,verbo…

代码随想录算法训练营29期|day34 任务以及具体任务

第八章 贪心算法 part03 1005.K次取反后最大化的数组和 class Solution {public int largestSumAfterKNegations(int[] nums, int K) {// 将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小nums IntStream.of(nums).boxed().sorted((o1, o2) -> Math.ab…

再学css

盒模型 有两种, IE盒子模型、W3C盒子模型;盒模型: 内容(content)、填充(padding)、边界(margin)、 边框(border);区 别: IE的content部分把 border 和 padding计算了进去; 标准盒子模型的模型图 从上图可以看到&#x…

Coremail启动鸿蒙原生应用开发,打造全场景邮件办公新体验

1月18日,华为在深圳举行鸿蒙生态千帆启航仪式,Coremail出席仪式并与华为签署鸿蒙合作协议,宣布正式启动鸿蒙原生应用开发。作为首批拥抱鸿蒙的邮件领域伙伴,Coremail的加入标志着鸿蒙生态版图进一步完善。 Coremail是国内自建邮件…

MIT6.1810/Fall 2022(which was called 6.S081 then) Lab5-7

Lab: Copy-on-Write Fork for xv6 8.4 Copy On Write Fork - MIT6.S081 先理解COW机制 Implement copy-on-write fork 您的任务是在xv6内核中实现写时复制分叉。如果修改后的内核成功地执行了cowtest和usertests -q程序,那么就完成了。 为了帮助您测试实现&#…

【计算机网络】——TCP协议

📑前言 本文主要是【计算机网络】——传输层TCP协议的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 🌄每日一句…

获取依赖aar包的两种方式-在android studio里引入 如:glide

背景:我需要获取aar依赖到内网开发,内网几乎代表没网。 一、 如何需要获取依赖aar包 方式一:在官方的github中下载,耗时不建议 要从开发者网站、GitHub 存储库或其他来源获取 ‘com.github.bumptech.glide:glide:4.12.0’ AAR 包&#xff…

下拉框联动 类似于请求第一个框之后,携带参数请求后端接口,渲染第二个下来框

直接上代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>1233</title></head><body><div><!-- <table><tr><td><div class"mdui-col"><input><…

PyTorch][chapter 12][李宏毅深度学习][Semi-supervised Linear Methods-1]

这里面介绍半监督学习里面一些常用的方案&#xff1a; K-means ,HAC, PCA 等 目录&#xff1a; K-means HAC PCA 一 K-means 【预置条件】 N 个样本分成k 个 簇 step1: 初始化簇中心点 (随机从X中抽取k个样本点作为&#xff09; Repeat: For all in X: 根据其到 &…

仿真APP在金属波纹管液压胀形工艺设计中的应用

一、背景介绍 金属波纹管是带有波纹状截面的金属管状零件&#xff0c;在工业中应用广泛。金属波纹管特殊的截面形状使其具备较好的柔韧性&#xff0c;能够在一定范围内伸缩弯曲。这一特性赋予波纹管两大用途&#xff1a;一是作为变形补偿器&#xff0c;可用于补偿管道设备由于…

转盘寿司 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 寿司店周年庆&#xff0c;正在举办优惠活动回馈新老用户。 寿司转盘上总共有 n 盘寿司&#xff0c; prices[i] 是第 i 盘寿司的价格。 如果客户选择了第 i 盘寿…