肖 sir_就业课__009ui自动化讲解

编程知识 更新时间:2023-05-03 01:27:14

ui自动化讲解
1、你做过自动化测试吗?做过 ui自动化测试、接口自动化、app自动化
2、你讲下你做的ui接口自动化?
(1)第一种:按照线性流程讲解 :python+selenium 库做ui自动化
(2)第二种:python+selenim+unittest 框架做的ui自动化
(2)第三种:po框架或则pom模型做ui自动化

3、自动化编写的规则
(1)熟悉场景写详细、不熟悉场景不写
(2)按场景讲解

4、
(1)第一种:按照线性流程讲解 :python+selenium 库做ui自动化
代码:
格式一:
自动化是使用python+selenium做的自动化,
我就以我最近做的xx项目讲下====一个场景(注册,登录,下单)的一个流程:
首先导入selenium 库 , 创建webdriver的对象driver,打开网站driver.get加上网址,让窗口最大化maxzewindow,设置一个时间等待,导入一个时间模块;打开页面f12查找注册按钮定位元素,元素有id,name,class,使用id=什么;
参考:

案例1:结合python+seleuim线性脚本

结合业务写UI自动化

(1)做ui自动化用的python+selenium库。 先导入selemiun中webdriver模块和time库中sleep模块。 我做自动化都是用的chrome浏览器或(ie、火狐等),然后下载对应驱动,创建对象driver=webdriver.chrome()调用驱动,通过对象driver去操作,通过用driver.get方法打开项目首页,在将浏览器最大化maximize_window,最大化是为了防止有些元素加载不完全或者点击不到。然后我会用一个implicitly_wait隐式等待方法,因为网速追不上程序的运行速度。如果是页面不跳转在页面加载元素的话,我会选择再用个sleep方法强制等待2S左右,因为不跳转的时候implictly wait不会生效,如果需要定位这些元素就会定位不到。 进入后先登录,通过link_text定位登录这个链接元素,用click点击,然后定位用户名输入框和密码输入框,用send_keys传入账户名和密码,然后用xpath定位确认登录按钮用click点击,登录就完成了。这个时候回跳转至首页。 项目首页就有投资模块的入口,用find_element_by_link__text找到元素然后用click点击,这个时候页面会跳转,跳转完是进入标的搜索页面,选择标的类型:正常的标投资或者债权转让,标的时间,我们项目是1月,2月,12个月,标的类型是用click就可以点击实现了,时间选择我们是个下拉框,需要先导入select模块,然后先select接这个元素,然后用select by index方法,选择1个对应的值。这里说明下我为什么用index,因为有时候会换中英文,或者value值,会导致脚本失败,而index就可以避免这种情况了。选择完这两个后等待元素的加载,这里也是用sleep,选择某一个标的投资按钮,也是用xpath定位然后click点击,这个时候页面新开一个确认投资窗口,这个时候就涉及到页面的切换,这里涉及到一个利用句柄handle切换窗口,先使用browser.window_handles获取所有句柄,索引位-1就是最新的窗口的,用switch_to_window()接新窗口的句柄就可以切换窗口了。然后用send_keys传入投资金额,支付密码,然后验证码是让开发同事写成了固定的字符,短信验证码关闭了。然后点击确认投资换这个button,也是用xptah定位,click点击。这个时候页面会跳转显示投资成功,这里我会用投资完成这个文本来做断言,用的是if not 加上assert false做的。然后就关闭浏览器用quit。然后前台的操作就完成了,再进入数据库校验数据,这里需要导入pymysql模块,然后用connect连接项目的数据库,用cursor获取游标,(游标就是一个数据的缓存区,用execute方法就可以吧sql语句取出来的临时表放入游标中,fetchall就可以把游标内的数据都是放在toupl容器中,通过索引位就可以把真实数据取出来做断言了)用execute接sql语句来获取对应的投资者在此项目的投资金额,在用fetchall取出此数据,断言这个数据是否等于我们在前台输入的投资金额。然后就断开数据库链接,关闭浏览器。这就是我的大概流程了。

梳理流程:

导入selenium选择浏览器创建对象通过对象get打开浏览器窗口最大化====时间等待(三种)====业务场景(id、name、class、css、xpath、link_txt、js方法)===比如一些控件(farm框、弹框、按钮、切换句柄、点击、输入)==断言(通过title、text)连接数据库区校验正确性
方式二:
自动化是使用python+selenium做的自动化,
我就以我最近做的xx项目讲下
一个场景(注册,登录,下单)的一个流程:
首先导入selenium 库 , 创建webdriver的对象driver,打开网站driver.get加上网址,让窗口最大化maxzewindow,设置一个时间等待,导入一个时间模块;打开页面f12,通多查找定位元素有id,name,class,css、xpath,js,link_txex ,tag_name 去定位,以及一些操
做send_key输入,click点击, 下拉框select ,单选框、多选框、按钮等;
(2)概括性说ui自动化
用的是python+selenium来做的,那我大概和您讲一下我做ui自动化的流程吧
答:首先的话就是我需要打开pycharm然后新建一个py模块,然后导入selenium模块,time模块等等,然后通过from selenium import webdriver语句导入webdriver模块,然后创建一个driver对象:driver=webdriver.Chrome(),再通过driver.get方法来打开我们测试环境的地址,再使用 driver.maximize_window()最大化浏览器窗口,然后会使用driver.implicitly_wait()设置一个隐式等待,我可以通过driver.find_element_by_id,或者xpath,name,class,css等元素定位方法来进行定位到用户名和密码输入框,并且通过调用send_keys进行输入用户名和密码,最后通过调用click方法进行登录,登录之后,有一些表单的填写页面(比如主要有姓名、证件信息、手机号码、常住地址、邮箱、紧急联系人等等),如果是输入框我依旧用send_keys,如果有一些下拉框我会导入Select类,通过select_by_value方法进行定位,如果有滑动的地方我也会用window.scrollTo()方法,设置变量为js,然后通过driver.execute_script()来调用js变量来达到滑动滚动条的目的,包括如果是有iframe弹框的话,我首先会通过switch_to.frame()进入到iframe弹框,然后再进行其他的操作,如果要退出iframe框的话,直接用switch_to.default_content()方法就可以了,最后写完整个一个流程之后,我还会通过调用text方法拿到某个元素的文本值赋值给到一个变量,然后通过assert方法把预期结果和实际结果进行一个断言,以上就是我做ui自动化的一个大致流程,但是这是我们最开始做ui自动化的方法,后面因为做的时间也比较久,用例也比较多,所以后续用了一些PO设计模式和分层对用例进行了一些封装

(3)代码

复制代码
from selenium import webdriver
from time import sleep
d=webdriver.Chrome()#通过对象谷歌浏览区且输入网址,在用get方法打开浏览区
url=“http://www.baidu/”
d.get(url)
sleep(2)
d.maximize_window()
sleep(3)
d.find_element_by_id(“kw”).send_keys(“dcs”)
复制代码

(3)第二种:python+selenim+unittest 框架做的ui自动化
unittest 框架作用:管理和执行自动化用例,方便后续维护测试用例
代码:

import  unittest
from  ui_zidonghua.selenium2 import *
from  ui_zidonghua.HTMLTestRunner3_New import   HTMLTestRunner
import time
class   Dcs(unittest.TestCase):
    @classmethod
    def  setUpClass(cls):#类的开始
        print('类的开始')
    @classmethod
    def   tearDownClass(cls):
        print("类结束")
    def setUp(self):
        print('方法开始')
    def  tearDown(self):
        print("方法结束")
    def test2(self):
        print('22222')
    def  test1(self):
        print('11111')
    def testA(self):
        print('AAAAA')
    def testa(self):
        print('aaaaa')
    def no(self):
        print('no')
if __name__ == '__main__':
    # unittest.main()# 第一种:运行所有的用例
   # tj=unittest.TestSuite()
   # # tj.addTest(Dcs('test1'))
   # tj.addTests([Dcs('test1'),Dcs('test2')])
   # r=unittest.TextTestRunner()
   # r.run(tj) @运行部分用例
   # xpath=r'C:\Users\Administrator\PycharmProjects\untitled6\ui_zidonghua'
#    # ss=unittest.defaultTestLoader.discover(start_dir=xpath,pattern="ui*.py")
#    # r=unittest.TextTestRunner()
#    # r.run(ss)#运行一份路径下的用例
   xpath=r'C:\Users\Administrator\PycharmProjects\untitled6\ui_zidonghua'
   ss=unittest.defaultTestLoader.discover(start_dir=xpath,pattern="ui*.py")
   new=time.strftime("%Y-%m-%d %H-%M-%S")
   filename=xpath+"/"+str(new)+"_ui.html"
   f=open(filename,"bw")
   r=HTMLTestRunner(
       stream=f,title="ui自动化报告",description="用例执行情况",tester="dcs"

   )
   r.run(ss)

讲解
案例2:结合unittest框架讲解

(1)我做ui自动化是通过Python+selenium+Unittest进行自动化测试,整个用例框它能帮我们比较规范的、系统的管理和执行用例,也便于后续的维护。下面我讲解下这个框架,首先需要导入unittest这个模块,我们做自动化的话还需要导入selenium这个模块,以及一些相关的模块,比方说time模块,OS模块,HTMLTestRunner报告模块。把我们需要的模块都导入,在unittest里我们需要去定义一个类,定义类名可以根据项目名定义,继承unittset.testcase,一个testcase的实例就是一个用例,类里需要有类的开始:setupclass,以及类的结束:teardownclass,在整个框架中只运行一次,然后在定义方法开始setup、方法结束teardown ,在用例每次执行中都会运行一次;然后我们需要去定义我们的用例,test1,test2,注意一定要以test开头,顺序按照ascii码1-9,大写A-Z,小写a-z,写完用例以后,我们需要去调用它,我们以main作为unittest的入口,执行自动化用例我们主要有4种调用的方式

第一种用unittest.main()去运行所有用例

第二种是创建一个套件TestSuite(),然后用addtest去添加你要执行的用例,这种方法可以执行部分测试用例,

第三种就是搜索绝对路径去执行自动化,调用unittest.testloader().discover()去搜索路径下的用例,在通过unittest.TextTestRunner() .run()方法执行搜索到用例

第四种是生成测试报告,搜索绝对路径去执行自动化,调用unittest.testloader.discover方法执行用例,然后把执行结果写入我们导入的报告模板文件,执行之后就能看到我们路径下所有用例的执行结果。

以上就是unittest框架的整个基本流程

(2)案例2:

我说下电商下单自动化测试流程吧,因为是基于unittest框架进行编写所以需要用import unittest导入unittest模块还需要导入webdriver模块因为需要用webdriver方法去调用谷歌浏览器的驱动来打开浏览器,然后先定义一个类在参数中输入unittest.testcase用来继承unittest.testcase中的类,然后定义setup方法在setup中先将webdriver.Chrome赋值给self.变量chrome是我用的谷歌浏览器的驱动,并用login.dl(self.变量)来调用之前封装好的登录功能,然后再定义一个test打头的函数这里主要用于编写实际测试用例,然后在test函数中将slef.变量再次进行赋值给一个变量方便于操作。接下来进行定位搜索栏,输入商品名称,点击搜索按钮,用F12获取xpath值然后用find_element_By_xpath对搜索栏进行定位并赋值给一个变量这里这里说下为啥用xpath进行定位,因为有时候id 和name 等属性值不是唯一的或者没有,所以直接使用xpath进行定位会比较好能解决百分90的定位问题,然后使用send_keys()去进行输入操作和click()进行点击按钮操作,此时页面中会搜索出我搜索的商品,仍然通过xpath定位和click()操作搜索出的商品页面会新开窗口进入商品详情页,这时候就需要用window handles获取所有窗口的句柄并赋值给一个变量,然后使用switch to window加变量索引值切换到新窗口,有时候网页会加载比较慢所以需要使用from time import sleep导入时间模块然后使用sleep等待3秒,确保网页加载完成后进行下一步操作,然后在用find_element by xpath.click选择商品的规格型号和商品数量,接下来通过find_element_by_xpath.text获取商品详情页中我选择的规格型号、商品数量、商品单价、订单小计/合计,通过find_element_by_xpath.click点击立即购买按钮,页面进入到确认订单页,然后通过find_element_by_xpath.text获取确认订单页规格型号、商品数量、商品单价、订单小计/合计与商品详情页选择的数据使用if判断进行比较,如果一致就print 成功,否则else pirnt失败,确保订单中的数据是我在商品详情页中选择的数据,再接下来点击提交订单操作进行下单,下单后通过调用封装好的数据库读取模块传参(ip/dbuser/dbpwd/dbname/sql)进行访问数据库中order库获取我的订单数据,然后用order库中获取的数据与下单的数据进行if判断比较判断数据库中的订单数据是否正确,如果正确就print 成功,否则else pirnt失败,然后就是定义teardown方法在teardown中用close命令关闭浏览器,然后就是进行调用执行,执行方法有三种第一种unittest.main(),main的话就是执行了testloader类中的方法帮我们搜索test开头的用例并执行,执行顺序是按ascll码分布顺序运行的,第二种方法是用unittest.testsuit()方法,先将unittest.testsuit赋值给一个变量,然后通过这个变量使用addtest命令添加用例,在使用unittest.testrunner中的run方法执行这个变量。执行顺序的化是按照添加的顺序执行的。第三种方法是用unittest.default testloader.discover(加用例存放的路径,pattern等于模块名)再赋值给一个变量,然后同样通过unittest.testrunner中的run方法执行这个变量,然后为了查看执行详情结果所以需要写入执行报告。写入执行报告的话需要先导入一个HTMLtestrunnerCN 模块使用这个模块中 的htmltestrunner来写入执行报告并存放到指定的路径中
代码:
import unittest
class Test(unittest.TestCase):
@classmethod #类方法
def setUpClass(cls) -> None:
print(“类的开始”)
@classmethod
def tearDownClass(cls) -> None:
print(“类的结束”)
def setUp(self) -> None:
print(“方法开始”)
def tearDown(self) -> None:
print(“方法结束”)
def test001(self): #测试用例1
print(1111)
def test002(self): #测试用例2
print(2222)
def testb(self): #测试用例3
print(‘bbbb’)
def testa(self): # 测试用例4
print(‘aaaa’)
def hz(self): # 测试用例5
print(‘hz’)
if name == ‘main’:
unittest.main() #unittest 单元测试调用所有
  
import unittest
from selenium import webdriver
from time import *
from ui_zidonghua.HTMLTestRunner3_New import HTMLTestRunner #导入报告模板
class Test_Baidu(unittest.TestCase):
def setUp(self) -> None: #方法开始
self.driver=webdriver.Chrome()
self.driver.get(“https://www.baidu/”)
self.driver.implicitly_wait(3)
def tearDown(self) -> None:
sleep(3)
self.driver.close()
def test001(self):
self.driver.find_element_by_id(“kw”).send_keys(“selenium”)
self.driver.find_element_by_id(“su”).click()
def test002(self):
self.driver.find_element_by_id(“kw”).send_keys(“python”)
sleep(2)
self.driver.find_element_by_id(“su”).click()
def test003(self):
self.driver.find_element_by_id(“kw”).send_keys(“html”)
sleep(2)
self.driver.find_element_by_id(“su”).click()
title=self.driver.title
self.assertEqual(title,“zhong”)
def hz(self):
self.driver.find_element_by_id(“kw”).send_keys(“hzdcs”)
sleep(2)
self.driver.find_element_by_id(“su”).click()
#def test_all_case(): #定义一个函数
suit=unittest.TestSuite() #创建一个套件或者是一个容器,作用用来装所有的测试的的对象
suit.addTest(Test_Baidu(‘test002’)) #addtest添加用例
#suit.addTests([Test_Baidu(‘test001’),Test_Baidu(‘test002’),Test_Baidu(‘test002’)],)
return suit
if name == ‘main’:
unittest.main() #第一种执行框架中全部用例
# runner=unittest.TextTestRunner()
# runner.run(test_all_case()) #第二种执行部分用例
#执行脚本的相对路径
# path=r"C:\Users\Administrator\PycharmProjects\untitled6\ui_zidonghua"
ss=unittest.defaultTestLoader.discover(start_dir=path,pattern=“test*.py”)
runner=unittest.TextTestRunner()
runner.run(ss) # 第三种方法 自动化搜索用例执行
# path=r"C:\Users\Administrator\PycharmProjects\untitled6\ui_zidonghua"
# ss=unittest.defaultTestLoader.discover(start_dir=path,pattern=“test*.py”)
# bgpath=path=r"C:\Users\Administrator\PycharmProjects\untitled6\ui_zidonghua"
# now=strftime(“%Y-%m-%d-%H-%M-%S”)
# filename=bgpath+“\”+str(now)+“_ui.html”
# f=open(filename,“bw”) #b 表示二进制的方法写入,w是写入
# runner=HTMLTestRunner(stream=f,title=“ui自动化测试报告”,description=“用例执行情况”,
# tester=“hz” )
# runner.run(ss) # 第三种方法 自动化搜索用例执行

TestCase:
一个Testcase的实例就是一个测试用例,测试用例就是一个完整的测试流程,包括初始化setUp、运行run、测试后的还原tearDown(字面意思,测试用例。为一个或多个方法提供测试方法。一般是一个test)
TestSuite:
对一个功能的测试往往需要多测试用例的,可以把多的测试用例集合在一起执行,这就是TestSuite的概念。常用addTest()方法将一个测试用例添加到测试套件中(测试集合,即一组测试。一个test suite是把多个相关测试归入一组的快捷方式)
TextTestRunner:
是用来执行测试用例的,其中的run(test)用来执行TestSuite/TestCase。测试的结果会保存在TextTestResult实例中(测试运行器。执行test suite的程序)
TestLoader:是用来搜索所有以test开头的测试用例,然后将其加入到testsuite中

======================================================================================

(2)第三种:po框架或则pom模型做ui自动化
po框架

(1)参考:https://wwwblogs/xiaolehua/p/14434567.html

讲解:

案例1:

ui自动化测试,我是用po框架做的,对自动化用例进行分层:先创建一个项目名称xx;在项目下创建对应的包,一般我是分为6个包

(1)先创建第一个cofing包==存放所有配置文件信息(比如项目路径和数据,用例的路径)

(2)在创建第二个Data包==放数据(测试数据)

(3)在创建第三个report包==存放测试报告

(4)在创建第四个包public公共公开包(存放一些功能用例);在这个包下面在创建两个子包:
pages包和utils包
a、在pages包中存放元素层流程层(封装所有页面的公共方法,基类)
b、在utils包(处理公共类公共函数都存放在此)
可以在utils中来读取pages中封装的登录的流程(封装读取ini文件或者EXCEL表格的工具类和工具函数
(5)在创建一个TestCase用例包用来存放用例
(6)在创建一个run_all用来运行
通过运行测试用例中封装好的用例在运行然后在repot中生成测试报告
这就是我的框架;
案例2:我讲解下我的框架,po框架,可以分成6层:如下

第1层的话是config配置层,这个里面主要是封装了一些我们测试环境的url地址和一些连接数据库的IP地址,用户名密码等等
第2层是utils工具类层,这个里面主要封装了一些读取Excel表格的工具类,还有发邮件的工具类,还有一些读取配置文件的工具类
第3层是一个public基类,这个里面主要封装了元素定位的方法比如把id,name,class,xpath,css等等都封装在一个类方法里面了,还把一些send_keys和隐式等待和其他其他公共方法都进行了二次的封装
第4层就是testcase用例层了,这个里面主要就是通过定义一个类然后继承unittest.TestCase这个类,通过unittest单元测试框架来管理用例,在setupclass里面去创建driver对象,然后通过设置和取值的方法,拿到driver对象,先编写登录的用例,然后这个里面也用到了PO设计模式,把我们的元素定位和流程层,代码层进行了分离,最后用例写完再通过self.assertEquals进行一个断言
第5层就是run运行层,首先会通过把所有的用例加载到一个suite套件里面,然后再通过调用run方法运行这个套件
第6层就是通过HTMLtestrunner模块生成测试报告,然后最后通过Jenkins做可持续集成,在回归测试阶段,每天晚上都会运行一下我们的ui自动化用例,大致的一个框架结构就是这样的。

案例3:

写自动化用例的时候我喜欢对用例进行分层处理。我一般会设置六个模块:公共模块、用例模块、执行模块、报告模块、数据模块、页面元素模块。
把一些公共的,经常调用的属性放到公共模块中,比如登录登退出啊,连接断开数据库等。
页面元素模块就是将页面定位和业务操作分开,分离测试对象(元素对象)和测试脚本(用例脚本),这样的话当页面元素变动的话我们只需要更改页面元素对象即可。
把用例的具体内容放到用例模块中,比如我要借款,通过设置一些类,再把我要借款相应的用例放到这下面,这样后续我进行维护就非常的直观方便。
执行模块就是对上面各个类的执行方法,要执行哪些类里的哪些用例和对应测试报告的生成。
报告模块就是存放生成测试报告的地方,这样我们就能一目了然的看到是哪些模块下的用例的执行情况。
数据模块的是就是存放一些数据的地方,比方说用户的账户密码,网址信息等。
就拿我要出借这个流程的举个例子讲解一下吧!首先导入相应的库 from selenium import webdriver ,import unittest。然后新建一个继承unittest.testcase类。然后在def setup里写一些前置条件:像是webdrvier.chrome()选择谷歌浏览器,用get方式?获取网址打开,用maximize.window进行浏览器最大化处理,避免出现页面中元素定位后无?法点击报错的现象,确保用例执行的准确性,因为有时候用例执行太快,而网页加载太慢会?导致报错,所以我一般都会用implicity_wait进行智能等待,确保页面加载完成。把登入写进了公共模块中直接调用他。
接下来定位我要出借,因为他是一个下拉列表,所以我们得先导入from selenium.webdriver.support.ui import Select模块,用 Select(dr.find_element_by_xpath(“ ”).select_by_index(1),通过索引位进行定位。这个时候会打开一个新页面,所以我们得定位到这个新页面。
首先我们先获取所以页面的句柄allhead=dr.window_handles,再用dr.switch_to_window(allhead[-1])定位到我要出借这个新页面,通过find_element_by_xpath定位对应的标,然后定位到投资金额框,至于输入金额的话为了提高效率,我是之前已经写好了随机生成整百金额的函数,所以我这边直接调用就可以了,至于验证码我之前就已经请开发帮我去掉了,然后定位确认投资按钮点击。接下来系统会弹出一个风险提示
揭示书,它是一个alter弹框,alter=driver.switch_to_alter()进入到alter弹框里,再用alter.accept()。
这时候为了保证用例执行的准确性,再用unittest框架中的断言,之后用if语句和assertEquals判断前后两个值是否相符如:(出借成功,出借失败),不相符的话用dr.get_screenshot_as_file(“d:\yy\erorr1.png”),最后到执行和生成报告了,用unittest中的testloader方法。
定义一个变量接收测试用例的目录,discover=unittest.defaultTestLoader.discover(测试用例的目录,“text*.py”)加载该目录下所有以text开头。
的Py文件。
导入生成报告所需的HTMLTestRunnerCN模块,用with open打开对应的报告文件,“wb”二进制方式写入,用HTMLTestRunnerCN里的runner方法生成测试报告。最后用runnrt.run(discover)方法执行之前加 载的用例就好了。
这就是之前公司用python加selenium做自动化测试的一个基本流程。

========================================================
一、自动化中遇到哪些问题?====>肖sir_自动化遇到问题归纳

(1)定位问题:

验证码、日历控件、弹框、定位属性的空格、内嵌滚动条、切换窗口、等

如:

(1)动态元素定位不到
解决方法:尽量使用固定元素定位,如没有固定元素,则采用绝对路径进行定位,因为元素路径是唯一且不变的
(2)自动化脚本执行速度较慢
尽量使用css方法定位元素,使用等待时,少用sleep方法,尽量不用隐式等待,涉及到一些if elif条件判断时,尽量把可能发生的条件放在前面写,这样可以减少程序判断的次数,提高效率

二、自动化面试题

1、你有做过自动化?你用什么语言? python
2、自动化中如何使用语言打开一个网址?浏览器,浏览器对应驱动,导入库,类,get,url
3、在一个浏览器中打开多个窗口?open_windows driver.execute_script
4、在自动化中如何释放资源? 当一个注意点,经验(不去quit,close)
5、如何切换窗口? switch_to_window(handle)
6、如何获取当前句柄?如何获取所有句柄?
7、如何获取当标题?如何获取所有标题?
8、如何在自动化输入文本?
9、如何点击按钮?
10、清除当前的内容的语句?
11、为什么使用时间等待?(使用时间的优点)
12、如何窗口最大化?
13、复现框如何多选或者全选?
14、单选框如何选择?
15、说一下自动化常用的定位方法? (9种)
16、下拉框如何定位?导入Select 类
17、iframe框如何定位?进入ifrme框的语句?ifrme退出框的语句?
18、弹框的定位?(确认型弹框,输入型弹框,alert弹框,)
19、自动化中本地文件上传?
20、如何定位滚动条?

更多推荐

肖 sir_就业课__009ui自动化讲解

本文发布于:2023-04-29 21:00:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/9c55832a75aa0948ba92309477649ae6.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:__009ui

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 112226文章数
  • 28547阅读数
  • 0评论数