使用wda框架实现IOS自动化测试详解

目录

1、weditor元素定位工具

1.1、weditor的安装和使用

2、wda iOS自动化框架

2.1、wda概述

2.2、wda安装

2.3、wda的使用

2.3.1、全局配置

2.3.2、创建客户端

2.3.3、APP相关操作

1、启动APP

2、关闭APP

3、获取APP状态信息

4、获取当前APP的运行信息

2.3.4、设备相关操作

1、回到主页面

2、调节音量

4、锁屏

5、屏幕截图

6、获取设备应用信息

4.3.5、等待

2.3.6、元素定位

1、id

2、className

3、value

4、label

5、name 和 text

6、组合定位

7、子元素定位

8、xpath

8.1、单属性定位

8.2、组合定位

8.3、层级定位

9、Predicate定位

10、classChain定位

11、获取单个元素

12、获取元素属性

4.3.7、元素操作

1、点击

2、轻敲

3、输入值和清除值

4、滑动

5、缩小放大

6、滚动

7、弹窗

使用tidevice工具启动WDA代理服务见文章:基于tidevice实现iOS app自动化使用详解-CSDN博客

1、weditor元素定位工具

  • 作用:使用weditor完成对iOS的元素定位,它也可以完成对Android的元素定位。

1.1、weditor的安装和使用

1、安装:

  • 注意:这里指定安装0.6.4版本的,如果默认安装最新的,很可能会出现安装失败的问题,这里推荐指定安装。

pip install weditor==0.6.4

2、启动weditor

python -m weditor

  • 运行命令后,会自动打开浏览器,默认页面如下

  • 模块选择iOS,默认连接是本地8100接口,点击Connect,出现以下错误提示:

3、启动WebDriverAgent服务

  • 出现上面错误是因为本机和iOS设备通信失败,需要使用tidevice启动WebDriverAgent程序,使本机和iOS设备可以正常通信。保持USB与iOS设备连接,执行以下命令:

tidevice wdaproxy -B WebDriverAgent_bundle_id --port 8100
# 指定设备启动WebDriverAgent
tidevice -u &UDID wdaproxy -B WebDriverAgent_bundle_id --port 8100

  • 执行命令出现以下提示说明WebDriverAgent服务启动成功:

  • 点击Connect重新连接,如果没有报错说明,连接成功;点击 Dump Hierarchy 可以同步当前设备的页面,检查是否可以正常同步页面,如手机上打开时钟app,然后点击 Dump Hierarchy 查看是否正常同步页面,正常结果可以同步 如下:

2、wda iOS自动化框架

2.1、wda概述

Facebook-wda库(wda是其简称)是一个基于WebDriverAgent的Python客户端库,用于实现iOS设备的自动化测试。下面是Facebook-wda库实现iOS自动化的底层原理:

  • WebDriverAgent:Facebook-wda库依赖于WebDriverAgent项目,这是一个由Facebook开源的iOS设备自动化测试框架。它是一个基于XCTest和XCUITest的服务,运行在iOS设备上,并提供了与设备进行通信的接口。
  • WebDriver协议:Facebook-wda库使用WebDriver协议与WebDriverAgent进行通信。WebDriver是一个标准化的浏览器自动化协议,Facebook-wda库通过发送HTTP请求并解析响应来控制iOS设备。
  • Appium的衍生项目:Facebook-wda库实际上是Appium项目的一个衍生项目。它在Appium的基础上进行了定制化的开发,并提供了更简洁、易用的API接口。因此,Facebook-wda库的底层原理与Appium类似,都是基于WebDriver协议与WebDriverAgent进行通信。

综上所述,Facebook-wda库通过WebDriver协议与iOS设备的WebDriverAgent进行通信,以实现iOS设备的自动化测试。它利用了WebDriverAgent作为中间件,将客户端的请求转化为XCTest和XCUITest代码,从而控制设备执行操作。通过这种方式,Facebook-wda库实现了iOS自动化测试的底层原理。

2.2、wda安装

pip3 install -U facebook-wda

2.3、wda的使用

2.3.1、全局配置

import wdawda.DEBUG = False  # default False
wda.HTTP_TIMEOUT = 180.0  # default 180 seconds
wda.DEVICE_WAIT_TIMEOUT = 180.0 # default 180 seconds

2.3.2、创建客户端

1、默认一个设备的情况

import wda# 等价于wda.Client()方式,默认服务地址为http://localhost:8100,且连接的设备只有一个的情况
c = wda.Client('http://localhost:8100')
# 检查连接状态,state为success表示连接成功
print(c.status())

2、使用USBClient创建客户端

  • 注意:
    • USBClient 是继承自Client
    • USBClient 连接wda服务是通过unix:/var/run/usbmuxd
    • 所以在Windows环境下执行会出现问题,可以使用Mac执行
# 只有一个设备的情况,可以不添加参数
c = wda.USBClient()# 指定设备的udid、WDA的端口号和wda_bundle_id连接
c = wda.USBClient("$UDID", port=8100, wda_bundle_id="$wda_bundle_id")# 通过DEVICE_URL访问
c = wda.Client("http+usbmux://{udid}:8100".format(udid="$UDID"))print(c.status())

2.3.3、APP相关操作

1、启动APP
# 注意每次启动都是冷启动,也就是如果app打开,会先kill掉,再启动
c.session("com.apple.Preferences")# 如果已启动且在后台会被拉起到前台
# 如果已启动且在前台,不做任何操作,结束
# 如果未启动,则冷启动该应用
c.session().app_activate("com.apple.Preferences")# 作用和app_activate()一样,但是支持更多的参数
c.session().app_start("com.apple.Preferences")
2、关闭APP
# 关闭APP
c.session().app_terminate("com.apple.Preferences")
3、获取APP状态信息
# 获取APP状态信息
print(c.session().app_state("com.apple.Preferences"))# 输出结果
{'value': 4, 'sessionId': 'B5976-F91E-444A-876E-1DA0', 'status': 0}
value 表示的意思 1: 未启动, 2: 驻留在后台, 4: 正在运行
4、获取当前APP的运行信息
# 获取当前APP的运行信息
print(c.app_current())

2.3.4、设备相关操作

1、回到主页面
# 回到手机主页面
c.home()
c.press("home") 
2、调节音量
# 调节音量
c.press("volumeUp")
c.press_duration("volumeUp", 3)  # 长按3s音量上键
c.press("volumeDown")
c.press_duration("volumeDown", 3)  # 长按3s音量下键
4、锁屏
c.locked() # 返回锁定状态True/False
c.lock()  # 锁屏
c.unlock()  # 解锁
5、屏幕截图
# 截图,save(fp) 传文件路径地址
c.screenshot().save("./tmp.png")from PIL import Image
# 旋转90度截屏(逆时针旋转)
c.screenshot().transpose(Image.ROTATE_90).save("./tmp2.png")
6、获取设备应用信息
# 查看设备状态信息
print(c.status())# 获取设备信息
print(c.device_info())# 获取电量信息
print(c.battery_info())# 获取分辨率
print(c.window_size())

4.3.5、等待

  • 说明:等待分为强制等待和隐式等待;
    • 强制等待:不管元素是否加载,都强制等待指定时间,实际根据具体情况进行配置,只在使用的地方生效。
    • 隐式等待:在规定时间内如果元素可操作,直接进行操作;不必强制等到指定的时间;如果超过规定的时间,元素不可进行操作会抛出异常。一般会在全局配置的时候进行统一配置,配置每一步的操作都会生效。
# 设置强制等待的时间为3秒,等价于:time.sleep(3)
c.sleep(3)# 设置隐式等待的时间为10
c.implicitly_wait(10)

2.3.6、元素定位

  • 注意:元素定位不只是在当前操作页面,如:浮层,弹窗等;而是整个当前的页面中,也就是如果当前操作的是浮层,浮层下面的元素也会被查找。可以使用find_elements()函数进行验证。
  • 这里只是进行元素定位,并没有进行任何操作。
1、id

通过id进行定位,这里的id是指页面元素字段identifier

c(id='element_id')

2、className
c(className="element_className")
3、value
c(value="element_value")
# 模糊查找
c(valueContains="part element_value")
4、label
c(label="element_label")
# 模糊查找
c(labelContains="part element_label")
5、name 和 text
  • name 和 text 使用一样,text只是name的一个别名,源码说明如下:

c(name="element_name")
# 模糊查找
c(nameContains="part element_name")
# 正则表达式
c(nameMatches="regex string")
6、组合定位
  • 通过不同属性的组合来完成最终元素的定位,注意:该方式定位一定是同一个层级的,如果是不同层级的则会定位失败。
c(className="element_className", name="element_name")
7、子元素定位
  • 该方式定义一定是父子层级的关系才能成功定位,不然会定位失败。
# 判断子元素是否存在
c(className='element_className').c(name='child_element_name').exists
8、xpath

xpath使用文档手册:xpath使用手册 - 简书

8.1、单属性定位

说明:单属性定位的前提是所选择定位的属性的值是唯一的才能准确定位;当然即使属性值不唯一,也可以进行定位,返回值默认是定位到的第一个元素。

书写格式: //*[@resource-id=’id属性’] 或 //*[contains(@resource-id, ‘部分id属性’)]

示例:

# 示例1:完全匹配
c(xpath="//*[@name='element_name']") 或 c.xpath("//*[@name='element_name']")# 示例2:模糊匹配
c(xpath="//*[contains(@name, 'element_name')]")

注:可以通过属性 id、value、label、name进行定位,注意:className属性识别不到,避免使用。

8.2、组合定位

说明:有时仅靠单一属性是很难准确定位的,这个时候就需要使用待定位元素的多个属性对该元素进行定位,通过 id、className、value、label、name这些属性任意组合实现准确定位

示例:

  • 1、通过name、value实现组合定位
print(c.xpath("//*[@name='element_name' and contains(@value, 'part element_value')]").exists)
  • 2、通过className、 label实现组合定位
    • 注意:取元素列表中的元素下标是从1开始的
print(c.xpath("//XCUIElementTypeCell[2]//*[@label='收入']").exists)
  • 3、通过name、rawIdentifier实现组合定位
print(c.xpath("//*[@name='element_name' and  @id='rawIdentifier_value')]").exists)
8.3、层级定位

说明:对于某些元素来说本身属性较少,无法通过组合定位的方式实现准确定位,那么就需要通过层级定位的方式实现准确定位,也就是通过其周围的元素来定位待定位元素

  • 1、父节点定位子节点
print(c.xpath("//XCUIElementTypeCell[2]//*[@label='收入']").exists)
  • 2、子节点定位父节点
    • 说明:/.. 表示上一级(上一层)
print(c.xpath("//*[@label='收入']/..").exists)
  • 3、子节点定位兄弟节点
    • 注意:这里是同一个层级的元素
print(c.xpath("//*[@label='收入']/..//*[contains(@label, '银行')]").exists)
  • 4、爷爷节点定位孙子节点
print(c.xpath("//*[@label='收入']/../..//XCUIElementTypeCell[3]//*[@name='晚餐']").exists)
9、Predicate定位

使用 Predicate 进行元素定位的优势:

  • 灵活性:Predicate 可以根据元素的属性、关系、状态等进行定位,提供了更灵活的定位方式。例如,可以使用 Predicate 定位名称包含特定文本、类型为特定类型、可见、可用等条件的元素。
  • 精确性:Predicate 可以定位唯一的元素,避免了使用类名、标签名等不唯一的属性进行定位时可能出现的误差。
  • 执行速度:相对于其他定位方式(如 XPath),Predicate 的执行速度较快,因为它不需要解析 DOM 树。
  • 可读性:Predicate 表达式比较简单,易于阅读和理解。在编写自动化脚本时,可以更快地识别 Predicate 表达式的意义和功能。

注意:默认情况下,字符串比较是大小写和变音敏感的,可以在关键字后面加上[cd],[c]不区分大小写,[d]表示不区分变音符号

基本比较

符号

说明

示例

=, ==

等于

name == “hello”

>

大于

label > 10

小于

label < 10

>=, =>

大于等于

label >= 10

小于等于

label

!=, <>

不等于

label != “hello”

集合操作

符号

说明

示例

ANY, SOME

满足表达式的任意元素

ANY value < 18

ALL

满足表达式的所有元素

ALL value < 18

NONE

不包含满足表达式的任意元素

NONE value < 18

IN

元素在集合中

name IN { ‘hello’, ‘world’ }

BETWEEN

位于某个范围

value BETWEEN { 0 , 33 }

array[index]

数组array中指定索引的元素

array[FIRST]

数组中的第一个元素

array[LAST]

数组中的最后一个元素

array[SIZE]

指定数组大小

布尔值

符号

说明

示例

TRUEPREDICATE

TRUE

FALSEPREDICATE

FALSE

逻辑运算符

符号

说明

示例

AND, &&

逻辑与

name="hello" AND label="hello"

OR, ||

逻辑或

NOT, !

逻辑非

字符串比较

关键字

说明

示例

BEGINSWITH

以某个字符串开始

name BEGINSWITH "hel"

ENDSWITH

以某个字符串结束

name ENDSWITH "lo"

CONTAINS

包含

name CONTAINS "llo"

LIKE

通配符

name LIKE '*llo'

MATCHES

正则匹配

value MATCHES '.*llo'

使用示例:

  • 1、通过name、label定位元素
print(c(predicate='name BEGINSWITH "工资" and label="工资到账"').exists)
  • 2、定位通过name定位元素,要求不区分大小写
print(c(predicate="name CONTAINS[c] 'llo'").exists)
  • 3、TRUEPREDICATE
    • 说明:
      • TRUEPREDICATE 表达式的使用方式主要是用于定位所有匹配的元素,因为它表示一个始终返回 true 的条件,因此不会对元素进行筛选和过滤。
      • 除了这种用法之外,TRUEPREDICATE 也可以用作其他表达式的一部分,以生成更复杂的 Predicate 表达式。例如,可以将 TRUEPREDICATE 与 AND 或 OR 等逻辑运算符结合使用,以实现更精细的筛选条件。
# 返回所有符合条件的元素
print(c(predicate="name CONTAINS[c] 'llo' AND TRUEPREDICATE").find_elements())
10、classChain定位

classChain 定位策略在某些情况具有以下优势:

  • 简洁和直观:使用 classChain 可以通过类名和关系描述元素的层级关系,使定位代码更加简洁和直观。
  • 定位精准:通过指定元素的类名和条件,可以更准确地定位到目标元素,避免了一些其他定位策略可能存在的歧义或模糊性。
  • 支持多层级关系:classChain 允许在不同的层级中选择元素,例如选择某个特定容器中的子元素,或者选择某个父元素下的兄弟元素,从而提供了更灵活的定位方式。
  • 减少定位冲突:由于 classChain 使用元素的类名和关系进行定位,相对于其他属性定位方式,可能更具唯一性,减少了定位冲突的可能性。

可以理解classChain是Predicate和Xpath定位的结合,搜索效率比XPath更高,可以直接查找子节点,不需要对整个页面进行遍历。

注意事项:在使用classChain定位是,一定要正确的知道页面的层级关系,可以通过c.source()函数查看页面结构。

示例:

  • 1、通过XCUIElementTypeWindow元素定位
    • 说明:表示应用程序的窗口元素。一个应用程序通常包含一个或多个窗口,每个窗口对应着一个界面或视图层级。窗口是应用程序的最顶层容器,包含了应用程序中的其他元素,如按钮、文本框、表格等。
print(c(classChain='XCUIElementTypeWindow').find_elements()) # 获取所有子窗口
print(c(classChain='XCUIElementTypeWindow[1]')) # 获取第二个窗口(索引下标从1开始)
print(c(classChain='XCUIElementTypeWindow[1]/*').find_elements()) # 获取第一个窗口下的所有子元素
print(c(classChain='XCUIElementTypeWindow[1]/*[1]').find_elements()) # 获取第一个窗口下的第一个子元素
print(c(classChain='XCUIElementTypeWindow[1]/XCUIElementTypeButton[1]').find_elements()) # 获取第一个窗口下的第一个XCUIElementTypeButton元素
  • 2、匹配任意层级的元素
    • ** :是通配符,表示匹配任意层级的元素
    • 注意:在[]中的表达是使用 `` 反引号括起来的(tab键上方那个键)
print(c(classChain='**/XCUIElementTypeCell/XCUIElementTypeStaticText[`label="工资收入"`]').exists) # 匹配所有Cell元素下满足label="工资收入"的Text元素
print(c(classChain='**/XCUIElementTypeCell[1]/XCUIElementTypeStaticText').find_elements()) # 获取第一个Cell元素下所有的Text元素
11、获取单个元素
  • 注意:index=0表示获取全部元素,默认为0
print(c(className="XCUIElementTypeStaticText", index=1).find_elements())
或
print(c(className="XCUIElementTypeStaticText")[1].find_elements())
12、获取元素属性
e = c("元素定位")print(e.className)
print(e.name)
print(e.visible)
print(e.value)
print(e.label)
print(e.text)
print(e.enabled)
print(e.displayed)
print(e.accessible)
print(e.bounds) # Rect(x=, y=, width=, height=)

4.3.7、元素操作

1、点击
c(className="XCUIElementTypeButton", name="1").click() # 点击元素
c(className="XCUIElementTypeButton", name="1").click_exists() # 判断是否可点击
c(className="XCUIElementTypeButton", name="1").click(timeout=1) # 设置超时等待时间单位秒c.click(x, y, duration) # 通过坐标点击 duration表示点击时长
2、轻敲
c(className="XCUIElementTypeButton", name="1").tap() # 和click一样
c(className="XCUIElementTypeButton", name="delet noire").tap_hold(3) # 长按3秒c.tap(x, y) # 通过坐标点击
c.tap_hold(x, y, duration) # 通过坐标点击 duration表示点击时长
c.double_tap(x, y) # 双击
3、输入值和清除值
c.xpath("//*[@label='搜索']").set_text('123') #  输入值
c.xpath("//*[@label='搜索']").clear_text() # 清除值
c.xpath("//*[@label='搜索']").set_text("\b\b\b")  # 删除3个字符,结尾也可以加\n 
c.xpath("//*[@label='搜索']").set_text('123\n') # 输入内容并确认,\n表示确认。类似输入完按Enter换行
4、滑动
c.swipe(x1, y1, x2, y2, duration=1) # 从(x1, y1)滑到(x2, y2),duration 持续时间 单位秒
c.swipe_left()        # 向左滑动
c.swipe_right()       # 向右滑动
c.swipe_up()          # 向上滑动
c.swipe_down()        # 向下滑动
5、缩小放大
# 放大 scale:缩放比例 speed:缩放速度  要求:scale>1 speed>0
c(className="Map").pinch(2, 1) # scale=2, speed=1
# 缩小,这里效果不好 要求:scale<1 speed<0
c(className="Map").pinch(0.1, -1) # scale=0.1, speed=-1
6、滚动
# irection 为 "up"、"down"、"left"、"right" 时,表示在指定方向上滚动。
# distance:滚动的距离,仅在 direction 不为 "visible" 时起作用。默认值为 1.0,表示元素的宽度或高度的倍数。
c(name="hello").scroll('down', 10) # 向下方向滚动hello元素宽度的 10 倍的距离(如果是向左/右 滚动元素的高度距离倍数)
7、弹窗
  • 弹窗的元素类型:XCUIElementTypeAlert
print(s.alert.exists)
print(s.alert.text)
s.alert.accept() # Actually do click first alert button
s.alert.dismiss() # Actually do click second alert button
s.alert.wait(5) # if alert apper in 5 second it will return True,else return False (default 20.0)
s.alert.wait() # wait alert apper in 2 seconds.alert.buttons()
# example return: ["设置", "好"]s.alert.click("设置")
s.alert.click(["设置", "信任", "安装"]) # when Arg type is list, click the first match, raise ValueError if no match
  • 弹窗监测
with c.alert.watch_and_click(['好', '确定']):s(label="Settings").click() # # 默认按钮值:["使用App时允许", "好", "稍后", "稍后提醒", "确定", "允许", "以后"]
with c.alert.watch_and_click(interval=2.0): # default check every 2.0s

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LLM之Agent(十一)| 多智能体框架CrewAI与AutoGen相比

基于LLM构建的Agent中有一个明显的现象就是多智能体体系结构的表现要超越单智能体&#xff0c;即使单智能体使用无可挑剔的提示策略。本文将探索另一个有趣的多智能体框架——CrewAI。 一、CrewAI整体优势 CrewAI可以应用在生成环境中。它在发言人的反应和编排上牺牲了一点灵活…

Unity | Spine动画记录

https://blog.csdn.net/linshuhe1/article/details/79792432 https://blog.csdn.net/winds_tide/article/details/128925407 1.需要的三个文件 通常制作好的 Spine 动画导出时会有三个文件&#xff1a; .png 、.json 和 .atlas&#xff1a; skeleton-name.json 或 skeleton-…

计算机网络_1.6.2 计算机网络体系结构分层的必要性

1.6.2 计算机网络体系结构分层的必要性 一、五层原理体系结构每层各自主要解决什么问题1、物理层2、数据链路层3、网络层4、运输层5、应用层 二、总结三、练习 笔记来源&#xff1a; B站 《深入浅出计算机网络》课程 本节主要介绍实现计算机网络需要解决哪些问题&#xff1f;以…

2017年苏州大学837复试机试C/C++

2017年苏州大学复试机试 要求 要求用C/C编程&#xff1b;对程序中必要的地方进行注释。上机规则 请在电脑桌面上新建一个文件夹文件夹名为考试姓名&#xff08;中文&#xff09;&#xff1b;考试完毕后&#xff0c;将所编写的文件放在上述文件中。 第一题&#xff08;20分&…

隧道穿透:常规反弹、加密反弹

目录 1、常规反弹 &#xff08;1&#xff09;Windows正向连接shell &#xff08;2&#xff09;Windows反向连接shell &#xff08;3&#xff09;Linux正向连接shell &#xff08;2&#xff09;利用Linux自带bash反弹Shell 2、加密反弹 1、常规反弹 假设在内网环境中发现…

一步步成为React全栈大师:从环境搭建到应用部署

文章目录 第一步&#xff1a;环境搭建第二步&#xff1a;了解React基础第三步&#xff1a;组件与路由第四步&#xff1a;状态管理第五步&#xff1a;接口与数据交互第六步&#xff1a;样式与布局第七步&#xff1a;测试第八步&#xff1a;构建与部署《深入浅出React开发指南》内…

【Java程序设计】【C00232】基于Springboot的抗疫物资管理系统(有论文)

基于Springboot的抗疫物资管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的抗疫物资管理系统 用户主要分为管理员和普通用户 管理员&#xff1a; 管理员可以对后台数据进行管理、拥有最高权限、具体权限有…

MySQL-----初识

一 SQL的基本概述 基本概述 ▶SQL全称: Structured Query Language&#xff0c;是结构化查询语言&#xff0c;用于访问和处理数据库的标准的计算机语言。SQL语言1974年由Boyce和Chamberlin提出&#xff0c;并首先在IBM公司研制的关系数据库系统SystemR上实现。 ▶美国国家标…

Quppy 注册教程,轻松通过欧洲银行同名转账绑定个人IBAN账号

Quppy 注册教程,轻松通过欧洲银行同名转账绑定个人IBAN账号 官网下载APP或者去香港区下载APP使用 https://quppy.com/ch/ 按照官方APP里的邮箱注册&#xff0c;填写邀请代码258258 能提升审核成功率&#xff0c;后添加电话和个人信息&#xff1b;需要说明的是&#xff1a;网站…

海外YouTube视频点赞刷单悬赏任务投资理财源码/tiktok国际版刷单理财

测试环境&#xff1a;Linux系统CentOS7.6、宝塔、PHP7.3、MySQL5.7&#xff0c;根目录public&#xff0c;伪静态Laravel5&#xff0c;开启SSL证书 前端&#xff1a;修改网站的默认文档 index.html 为第一个&#xff0c; index.php 改成第二个 &#xff0c;或者前端访问 index.…

【android】 android->profile 查看内存泄露

目录 实例讲解 各字段解释 实例讲解 各字段解释 在 Android Studio 的 Profile 视图中&#xff0c;Arrange by Stack 用于对内存分配和释放事件进行堆栈排列&#xff0c;以便更好地了解内存使用情况。以下是表上各列的一般含义&#xff1a; 1. **Call Chart (调用图)**: …

【DDD】学习笔记-领域场景分析实践

在先启阶段&#xff0c;我们确定了 EAS 的问题域与核心的业务流程&#xff0c;然后根据业务期望与愿景确定项目的业务范围&#xff0c;明确史诗级故事和主故事。这个过程既有利于我们对项目的整体理解&#xff0c;以便于确定需求列表、排定需求的优先级从而制订发布与迭代计划&…

一文教你地平线旭日派X3部署yolov5从训练-->转模型-->部署

一文教你地平线旭日派X3部署yolov5从训练&#xff0c;转模型&#xff0c;到部署 近日拿到了地平线的旭日派X3&#xff0c;官方说是支持等效5tops的AI算力&#xff0c;迫不及待的想在上面跑一个yolov5的模型&#xff0c;可谓是遇到了不少坑&#xff0c;好在皇天不负有心人&…

车载技术提升系列——CANape快速入门

车载技术提升系列——CANape快速入门 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己…

Qt中的线程与信号槽

小实践 mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H // #pragma once #include <QMainWindow> #include"zthread.h"QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass ZThread;class MainWindow : public QMainWin…

C++棋类小游戏2

今天给大家带来我花了1周时间自创的小游戏的升级版&#xff0c;博主还是一名小学生&#xff0c;希望大家提提意见。这是我写的最长的C代码&#xff0c;希望大家喜欢&#xff0c;不要抄袭&#xff0c;任何编译器都可以。 以前版本——C自创棋类小游戏-CSDN博客 C内容提示&…

苹果CMS挖片网升级版视频主题模版源码

自适应视频站正版高级挖片网收录模板&#xff0c;模板不错&#xff0c;是挖片网的升级版。 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88799583 更多资源下载&#xff1a;关注我。

RCS系统之:地图编辑

一般每个供应商都有不同的需求&#xff0c;不同的需求都会是在不同的场景下产生的。而不同的场景都会需要构建不同的地图数据。 所有一个动态编辑的地图的能力都软件&#xff0c;是非常有必要的。基于这个想法&#xff0c;我们提供了一个可以实时&#xff0c;动态编辑地图的界面…

7000字详解Spring Boot项目集成RabbitMQ实战以及坑点分析

本文给大家介绍一下在 Spring Boot 项目中如何集成消息队列 RabbitMQ&#xff0c;包含对 RibbitMQ 的架构介绍、应用场景、坑点解析以及代码实战。 我将使用 waynboot-mall 项目作为代码讲解&#xff0c;项目地址&#xff1a;https://github.com/wayn111/waynboot-mall。本文大…

红日靶场1搭建渗透

环境搭建 下载好镜像文件并解压&#xff0c;启动vmware 这里我用自己的win7 sp1虚拟机作为攻击机&#xff0c;设置为双网卡NAT&#xff0c;vm2 其中用ipconfig查看攻击机ip地址 设置win7 x64为双网卡&#xff0c;vm1&#xff0c;vm2 设置win08单网卡vm1&#xff0c;win2k3为单…