JavaApp自动化测试系列[v1.0.1][常用技巧]

news/2024/7/23 22:41:25 标签: TestListener, ITestResult

处理截图

通过监听器

package org.davieyang.testscripts;
import java.io.File;
import java.io.IOException;
import io.appium.java_client.AppiumDriver;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;

public class ScreenshotListener extends TestListenerAdapter{
    /**
     * 监听器是一些预定义的java接口,创建这些接口的实现类
     * 然后将其加入TestNG中,TestNG会在测试运行的不同时刻调用这些类中的接口方法
     * 实现ITestListener监听器的onTestFailure在测试失败的时候,保存控件截图
     */
    @Override
    public void onTestFailure(ITestResult iTestResult) {
        super.onTestFailure(iTestResult);
        AppiumDriver driver = Screenshot.getDriver();
        File file = new File("screenshots");
        String screenShotName = file.getAbsolutePath() + File.separator + iTestResult.getMethod().getMethodName()+".png";
        File screenShot = driver.getScreenshotAs(OutputType.FILE);
        try{
            FileUtils.copyFile(screenShot, new File(screenShotName));
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

截图的几种尝试

package org.davieyang.testscripts;
import java.io.File;
import java.io.IOException;
import io.appium.java_client.AppiumDriver;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;

public class ScreenshotListener extends TestListenerAdapter{
    /**
     * 监听器是一些预定义的java接口,创建这些接口的实现类
     * 然后将其加入TestNG中,TestNG会在测试运行的不同时刻调用这些类中的接口方法
     * 实现ITestListener监听器的onTestFailure在测试失败的时候,保存控件截图
     */
    @Override
    public void onTestFailure(ITestResult iTestResult) {
        super.onTestFailure(iTestResult);
        AppiumDriver driver = Screenshot.getDriver();
        File file = new File("screenshots");
        String screenShotName = file.getAbsolutePath() + File.separator + iTestResult.getMethod().getMethodName()+".png";
        File screenShot = driver.getScreenshotAs(OutputType.FILE);
        try{
            FileUtils.copyFile(screenShot, new File(screenShotName));
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

处理Toast

Toast是Android中用来显示信息的一种机制,和Dialog不一样,它没有焦点,而且显示的时间有限,很快就消失,Toast是Android的系统特性,不是应用特性,因此通过UI Automator Viewer无法获取控件

图片对比

Toast被触发后,截图对比

WebElement imagebtn = driver.findElementById("ShowToastButton");
imagebtn.click();
try{
	// 通过getScreenshotAs方法来捕捉屏幕,使用OutputType.File作为参数传递给getScreenshotAs方法
	// 告诉它将截取的屏幕以文件的形式返回
	File scrFile = driver.getScreenshotAs(OutpuType.File);
	// 使用copyFile保存getScreenshotAs截取的屏幕文件到D盘中并命名为scrshot.png
	FileUtils.copyFile(scrFile, new File("D:\\scrshot.png"));
}catch(Exception e){
	e.printStackTrace();
}

Selendroid方法

Selendroid方法(自动化测试引擎)可以识别Toast控件,采用WaitForElement方法获得Toast文本

waitForElement(By.partialLinkText("Hello seledroid toast"), 4, driver);

Automator2

在新版本的Appium中,使用Automator2自动化测试引擎,可以获取Toast

package org.davieyang.testscripts;
import static org.testng.Assert.assertNotNull;
import io.appium.java_client.android.Activity;
import io.appium.java_client.android.AndroidDriver;
import java.io.File;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;

public class ToastDemo {
    AndroidDriver<WebElement> driver;
    @BeforeMethod
    public void setUp()throws Exception{
        File appDir = new File("D:\\");
        File app = new File(appDir, "selendroid-test-app-0.17.0.apk");
        DesiredCapabilities cap = new DesiredCapabilities();
        cap.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
        cap.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
        cap.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
        driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), cap);
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    }
    
    @Test
    public void testToast(){
        Activity activity = new Activity("io.selendroid.testapp", ".HomeScreenActivity");
        driver.startActivity(activity);
        WebElement toastButton = null;
        toastButton = driver.findElement(By.id("io.selendroid.testapp:id/showToastButton"));
        toastButton.click();
        final WebDriverWait wait = new WebDriverWait(driver, 10);
        assertNotNull(wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@text='Hello selendroid toast!']"))));
    }
    
    @AfterMethod
    public void TearDown(){
        driver.quit();
    }
}

并行测试

Appium提供了一种方式以在一台设备上自动操作多个会话,也就是采用多个标识符的方式启动多个Appium服务器端从而实现测试并行执行,例如启动两个Appium服务器,第一个服务器Server Port设置为4723,Bootstrap Port设置为4724;第二个服务器Server Port设置为4725,Bootstrap Port设置为4726

提取Desired Capabilities

package org.davieyang;

public class Constants {
    public class RedMi3{
        public static final String deviceName = "Redmi3";
        public static final String udid = "claeae297d72";
        public static final String platformVersion = "5.1.1";
        public static final String platformName = "Android";
        public static final String appPackage = "io.selendroid.testapp";
        public static final String appActivity = ".HomeScreenActivity";
        public static final String unicodeKeyboard = "True";
        public static final String noSign = "True";
    }

    public class RedMi4{
        public static final String deviceName = "Redmi4";
        public static final String udid = "claeae297d73";
        public static final String platformVersion = "6.1.1";
        public static final String platformName = "Android";
        public static final String appPackage = "io.selendroid.testapp";
        public static final String appActivity = ".HomeScreenActivity";
        public static final String unicodeKeyboard = "True";
        public static final String noSign = "True";
    }
}

测试代码

package org.davieyang.testscripts;
import java.net.URL;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import org.testng.Assert;
import org.davieyang.Constants;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;


public class TestParallelRunDemo1 {
    AndroidDriver<AndroidElement> driver;
    @BeforeMethod
    @Parameters({"device_ID", "port"})
    public void setUp() throws Exception{
        // Desired Capabilities;
        // Define driver
    }

    @Test
    public void testWebApp(){
        System.out.println("TestScripts");
    }

    @AfterMethod
    public void TearDown(){
        driver.quit();
    }
}


package org.davieyang.testscripts;
import java.net.URL;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import org.testng.Assert;
import org.davieyang.Constants;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.NoSuchElementException;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import org.openqa.selenium.By;


public class TestParallelrundemo2 {
    AndroidDriver<AndroidElement> driver;
    @BeforeMethod
    @Parameters({"device_ID", "port"})
    public void setUp() throws Exception{
        // Desired Capabilities;
        // Define driver
    }

    @Test
    public void testWebApp(){
        System.out.println("TestScripts");
    }

    @AfterMethod
    public void TearDown(){
        driver.quit();
    }
}

配置testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="All Test Suite" parallel="tests" thread-count="2">
    <test verbose="2" preserve-order="true" name="parallelRunDemo1">
        <parameter name="device_ID" value="127.0.0.1"/>
        <parameter name="port" value="4723"/>
        <classes>
            <class name="org.davieyang.testscripts.TestParallelRunDemo1">
            <methods>
                <include name="testWebApp"/>
            </methods>
        </class>
        </classes>
    </test>
    <test verbose="2" preserve-order="true" name="parallelRunDemo2">
        <parameter name="device_ID" value="127.0.0.1"/>
        <parameter name="port" value="4725"/>
        <classes>
            <class name="org.davieyang.testscripts.TestParallelrundemo2">
            <methods>
                <include name="testWebApp"/>
            </methods>
        </class>
        </classes>
    </test>
</suite>

日志系统

在开始之前请确保已经掌握

JavaApp自动化测试系列[v1.0.0][Appium数据驱动测试框架]
JavaApp自动化测试系列[v1.0.0][Appium数据驱动测试框架之公共类库]
单元测试系列[v1.0.0][Log4j]

配置POM

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

配置log4j.properties

log4j.rootLogger=info, toConsole, toFile
log4j.appender.file.encoding=UTF-8
log4j.appender.toConsole=org.apache.log4j.ConsoleAppender
log4j.appender.toConsole.Target=System.out
log4j.appender.toConsole.layout=org.apache.log4j.PatternLayout
log4j.appender.toConsole.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%p] %m%n
log4j.appender.toFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.toFile.file=result/log/testlog.log
log4j.appender.toFile.append=false
log4j.appender.toFile.Threshold=info
log4j.appender.toFile.layout=org.apache.log4j.PatternLayout
log4j.appender.toFile.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%p] %m%n

测试代码引入日志

package com.davieyang.testscripts;
import com.davieyang.util.DataProviderFromCsv;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import com.davieyang.pages.HomePage_PF;
import com.davieyang.pages.RegisterPage_PF;
import com.davieyang.pages.RegisterVerifyPage_PF;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.apache.log4j.Logger;
import com.davieyang.base.BaseActivity;
import com.davieyang.util.Constants;
public class TestRegisterIII extends BaseActivity{

    Logger log = Logger.getLogger(TestRegisterIII.class.getName());
    
    AndroidDriver<AndroidElement> driver;
    @DataProvider(name="RegisterData", parallel = true)
    public static Object[][] getRegisterData() throws Exception{
        return DataProviderFromCsv.getTestData(Constants.注册页面I.filepath+ "/" +Constants.注册页面I.filename);
    }
    
    @Test(dataProvider = "RegisterData")
    public void test_Register_success(String no, String testName, String username, String eMail, String password, String name,
                                      String prolanguage, String accept, String verifyusername, String verifyeMail, String verifypassword,
                                      String verifyname, String verifyprolanguage, String verifyaccept) throws IllegalArgumentException, Exception{


        HomePage_PF homePage_pf = null;
        RegisterPage_PF registerPage_pf = null;
        RegisterVerifyPage_PF registerVerifyPage_pf = null;
        try{
            log.info("初始化home页面");
            homePage_pf = new HomePage_PF(getDriver());
            log.info("点击注册按钮,跳转到注册页面");
            registerPage_pf = homePage_pf.navigate_register_page();
            log.info("调用注册成功方法,传入参数");
            registerVerifyPage_pf = registerPage_pf.register_sucess(username, eMail, password, name, prolanguage, accept);
        }catch (AssertionError error){
            log.info("调用注册成功方法失败");
            Assert.fail("调用注册成功方法失败");
        }

        try{
            log.info("断言注册验证页面是否包含输入的name值");
            Assert.assertEquals(registerVerifyPage_pf.get_name_value(), name);
        }catch (AssertionError nameerror){
            log.info("断言失败");
            Assert.fail("name断言失败,查看name值是否正确");
        }

        try{
            log.info("断言注册验证页面是否包含输入的username值");
            Assert.assertEquals(registerVerifyPage_pf.get_username_value(), username);
        }catch (AssertionError usernameerror){
            log.info("断言失败");
            Assert.fail("username断言失败,查看username值是否正确");
        }

        try{
            log.info("断言注册验证页面是否包含输入的password值");
            Assert.assertEquals(registerVerifyPage_pf.get_password_value(), password);
        }catch (AssertionError passworderror){
            log.info("断言失败");
            Assert.fail("password断言失败,查看password值是否正确");
        }

        try{
            log.info("断言注册验证页面是否包含输入的preferedProgrammingLanguage值");
            Assert.assertEquals(registerVerifyPage_pf.get_preferedProgrammingLanguage_value(), prolanguage);
        }catch (AssertionError prolanguageerror){
            log.info("断言失败");
            Assert.fail("prolanguage断言失败,查看prolanguage值是否正确");
        }

        try{
            log.info("断言注册验证页面是否包含输入的email值");
            Assert.assertEquals(registerVerifyPage_pf.get_email_value(), eMail);
        }catch (AssertionError eMailerror){
            log.info("断言失败");
            Assert.fail("eMail断言失败,查看eMail值是否正确");
        }

        try{
            log.info("断言注册验证页面是否包含输入的accept值");
            Assert.assertEquals(registerVerifyPage_pf.get_acceptAdds_value(), accept);
        }catch (AssertionError accepterror){
            log.info("断言失败");
            Assert.fail("accept断言失败,查看accept值是否正确");
        }
        
    }
}

页面对象引入日志

HomePage
package com.davieyang.pages;
import io.appium.java_client.android.AndroidDriver;

// PageFactory
import org.openqa.selenium.support.PageFactory;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.iOSXCUITFindBy;
import io.appium.java_client.MobileElement;

import java.util.logging.Logger;


public class HomePage_PF {
    AndroidDriver<?> driver;
    Logger log = Logger.getLogger(HomePage_PF.class.getName());
    public HomePage_PF(AndroidDriver<?> driver){
        this.driver = driver;
        PageFactory.initElements(new AppiumFieldDecorator(driver), this);
    }

    // 页面对象时别,进入注册页面
    @AndroidFindBy(id="startUserRegistration")
    @iOSXCUITFindBy(id="startUserRegistration")
    public MobileElement startRegister_btn;

    // 单击注册页面按钮,进入注册页面,返回注册页面对象
    public RegisterPage_PF navigate_register_page(){
        log.info("在HomePage里点击按钮,进入register页面");
        this.startRegister_btn.click();
        return new RegisterPage_PF(driver);
    }
}
RegisterPage
package com.davieyang.pages;
import java.util.List;
import java.util.logging.Logger;

import io.appium.java_client.android.AndroidDriver;

import org.openqa.selenium.support.PageFactory;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.iOSXCUITFindBy;
import io.appium.java_client.MobileElement;

public class RegisterPage_PF {
    Logger log = Logger.getLogger(RegisterPage_PF.class.getName());
    AndroidDriver<?> driver;
    public RegisterPage_PF(AndroidDriver<?> driver){
        this.driver = driver;
        PageFactory.initElements(new AppiumFieldDecorator(driver), this);
    }


    // 页面对象时别
    // 用户名
    @AndroidFindBy(id="inputUsername")
    @iOSXCUITFindBy(id="inputUsername")
    public MobileElement username_txt;

    // 邮箱
    @AndroidFindBy(id="inputEmail")
    @iOSXCUITFindBy(id="inputEmail")
    public MobileElement email_txt;

    // 密码
    @AndroidFindBy(id="inputPassword")
    @iOSXCUITFindBy(id="inputPassword")
    public MobileElement password_txt;


    // 姓名
    @AndroidFindBy(id="inputName")
    @iOSXCUITFindBy(id="inputName")
    public MobileElement name_txt;

    // 编程语言
    @AndroidFindBy(id="input_preferedProgrammingLanguage")
    @iOSXCUITFindBy(id="input_preferedProgrammingLanguage")
    public MobileElement language_sel;
    public List<MobileElement> prgLanguage;

    // 是否确认注册
    @AndroidFindBy(id="input_adds")
    @iOSXCUITFindBy(id="input_adds")
    public MobileElement accept_check;

    // 注册按钮
    @AndroidFindBy(id="btnRegisterUser")
    @iOSXCUITFindBy(id="btnRegisterUser")
    public MobileElement register_btn;

    public RegisterVerifyPage_PF register_sucess(String username, String email, String password, String name,
                                              String language, String check){
        log.info("在Register页面输入username");
        this.username_txt.sendKeys(username);
        log.info("在Register页面输入email");
        this.email_txt.sendKeys(email);
        log.info("在Register页面输入password");
        this.password_txt.sendKeys(password);
        log.info("在Register页面清空name编辑框");
        this.name_txt.clear();
        log.info("在Register页面输入name");
        this.name_txt.sendKeys(name);
        log.info("在Register页面单击选择语言,弹出语言选择框");
        this.language_sel.click();
        log.info("在Register页面,弹出的语言选择框,选择语言");
        checkedTextView(language);
        log.info("在Register页面,选择accept_check");
        if(check.equals("Yes")){
            if(!this.accept_check.isSelected())
                this.accept_check.click();
        }
        log.info("在Register页面,单击注册");
        this.register_btn.click();
        return new RegisterVerifyPage_PF(driver);
    }

    public void checkedTextView(String language){
        // 使用class属性选择所有的单选按钮,并存放在一个list中
        @SuppressWarnings("unchecked")
        List<MobileElement> checkTextViews = (List<MobileElement>) driver
                .findElementsByClassName("android.widget.CheckedTextVeiw");
        // 使用for循环将List中的每个单选按钮进行遍历,查找name值为Ruby的单选按钮
        // 如果该按钮未处于选中状态则调用click方法进行选择
        for (MobileElement checkedTextView:checkTextViews){
            if(checkedTextView.getAttribute("name").equals(language)){
                if(!checkedTextView.isSelected()){
                    checkedTextView.click();
                }
            }
        }
    }
}

RegisterVerifyPage
package com.davieyang.pages;
import org.openqa.selenium.By;
import io.appium.java_client.android.AndroidDriver;

import org.openqa.selenium.support.PageFactory;
import io.appium.java_client.pagefactory.iOSXCUITFindBy;
import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.MobileElement;

import java.util.logging.Logger;

public class RegisterVerifyPage_PF {
    Logger log = Logger.getLogger(RegisterVerifyPage_PF.class.getName());
    AndroidDriver<?> driver;
    public RegisterVerifyPage_PF(AndroidDriver<?> driver){
        this.driver = driver;
        PageFactory.initElements(new AppiumFieldDecorator(driver), this);
    }

    // 页面对象识别
    @AndroidFindBy(id="label_name_data")
    @iOSXCUITFindBy(id="label_name_data")
    public MobileElement label_name_data;

    // 页面对象识别
    @AndroidFindBy(id="label_username_data")
    @iOSXCUITFindBy(id="label_username_data")
    public MobileElement label_username_data;

    // 页面对象识别
    @AndroidFindBy(id="label_password_data")
    @iOSXCUITFindBy(id="label_password_data")
    public MobileElement label_password_data;


    // 页面对象识别
    @AndroidFindBy(id="label_email_data")
    @iOSXCUITFindBy(id="label_email_data")
    public MobileElement label_email_data;

    // 页面对象识别
    @AndroidFindBy(id="label_preferedProgrammingLanguage_data")
    @iOSXCUITFindBy(id="label_preferedProgrammingLanguage_data")
    public MobileElement label_preferedProgrammingLanguage_data;

    // 页面对象识别
    @AndroidFindBy(id="label_acceptAdds_data")
    @iOSXCUITFindBy(id="label_acceptAdds_data")
    public MobileElement label_acceptAdds_data;

    // 增加验证项,返回验证值
    public String get_name_value(){
        log.info("在VerifyRegisterPage页面通过输入获取name值");
        return this.label_name_data.getTagName().toString();
    }

    // 增加验证项,返回验证值
    public String get_username_value(){
        log.info("在VerifyRegisterPage页面通过输入获取username值");
        return this.label_username_data.getTagName().toString();
    }
    // 增加验证项,返回验证值
    public String get_password_value(){
        log.info("在VerifyRegisterPage页面通过输入获取password值");
        return this.label_password_data.getTagName().toString();
    }
    // 增加验证项,返回验证值
    public String get_email_value(){
        log.info("在VerifyRegisterPage页面通过输入获取email值");
        return this.label_email_data.getTagName().toString();
    }
    // 增加验证项,返回验证值
    public String get_preferedProgrammingLanguage_value(){
        log.info("在VerifyRegisterPage页面通过输入获取preferedProgrammingLanguage值");
        return this.label_preferedProgrammingLanguage_data.getTagName().toString();
    }
    // 增加验证项,返回验证值
    public String get_acceptAdds_value(){
        log.info("在VerifyRegisterPage页面通过输入获取acceptAdds值");
        return this.label_acceptAdds_data.getTagName().toString();
    }


}

公共类库引入日志

package com.davieyang.base;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import java.net.URL;
import java.util.logging.Logger;

import org.apache.log4j.PropertyConfigurator;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.ITestContext;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;

public class BaseActivity {
    public static Logger log = Logger.getLogger(BaseActivity.class.getName());
    AndroidDriver<AndroidElement> driver;

    @BeforeClass
    public void startTest(ITestContext context) throws Exception{
        PropertyConfigurator.configure("config/log4j.properties");
        log.info("--------测试开始----------");
        DesiredCapabilities cap = new DesiredCapabilities();
        cap.setCapability("deviceName", "Remi 3");
        cap.setCapability("udid", "claeae297d72");
        cap.setCapability("platformVersion", "5.1.1");
        cap.setCapability("platformName", "Android");
        cap.setCapability("appPackage", "io.selendroid.testapp");
        cap.setCapability("appActivity", ".HomeScreenActivity");
        cap.setCapability("unicodeKeyboard", "True");
        cap.setCapability("noSign", "True");
        driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), cap);
    }

    @AfterClass
    public void endTest(){
        log.info("-----测试结束-----");
        driver.quit();
    }

    public AndroidDriver<AndroidElement> getDriver(){
        return driver;
    }
}


http://www.niftyadmin.cn/n/5546799.html

相关文章

uni-app三部曲之一: Pinia使用

1.引言 最近在学习移动端的开发&#xff0c;使用uni-app前端应用框架&#xff0c;通过学习B站的视频以及找了一个开发模板&#xff0c;终于是有了一些心得体会。 B站视频1&#xff1a;Day1-01-uni-app小兔鲜儿导学视频_哔哩哔哩_bilibili B站视频2&#xff1a;01-课程和uni的…

Django学习收尾

启动项目命令 python manage.py runserver 文件上传功能实现 title "Form上传"if request.method "GET":form UpForm()return render(request, upload_form.html, {"form": form, "title": title})form UpForm(datarequest.POS…

假期笔记1:anaconda的安装与pycharm中的引用

1.下载安装 Download Anaconda Distribution | Anaconda 2.填个邮箱 11111.. 3.下载。有点需要时间 4.安装&#xff0c;双击&#xff0c;根据实际进行&#xff0c;记清安装路径 5。环境设置 conda -V 6.创建环境 conda create --name env_name conda create --na…

纯前端如何实现Gif暂停、倍速播放

前言 GIF 我相信大家都不会陌生&#xff0c;由于它被广泛的支持&#xff0c;所以我们一般用它来做一些简单的动画效果。一般就是设计师弄好了之后&#xff0c;把文件发给我们。然后我们就直接这样使用&#xff1a; <img src"xxx.gif"/>这样就能播放一个 GIF …

单对以太网连接器多场景应用

单对以太网连接器应用场景概述 单对以太网&#xff08;Single Pair Ethernet&#xff0c;简称SPE&#xff09;作为一种新兴的以太网技术&#xff0c;以其独特的优势在多个领域得到了广泛的应用。SPE通过单对电缆进行数据传输&#xff0c;支持高速数据传输&#xff0c;同时还能…

【python技巧】pytorch网络可视化

参考 https://blog.csdn.net/qq_40726937/article/details/106122082 1. graphviz torchviz 环境安装简单 pip install torchviz pip install graphviz代码 import torch from torchvision import model from torchviz import make_dotmodels models.resnet18() x torc…

Interpretability 与 Explainability 机器学习

「AI秘籍」系列课程&#xff1a; 人工智能应用数学基础人工智能Python基础人工智能基础核心知识人工智能BI核心知识人工智能CV核心知识 Interpretability 模型和 Explainability 模型之间的区别以及为什么它可能不那么重要 当你第一次深入可解释机器学习领域时&#xff0c;你会…

git只列出本地分支

git只列出本地分支 git branch --list git强制删除本地分支 git branch -D_error: the branch dlx-test is not fully merged. -CSDN博客文章浏览阅读648次。git branch -d 可以通过: git branch 查看所有本地分支及其名字&#xff0c;然后删除特定分支。git删除远程remote分支…