Appium Android自动化测试框架设计核心指南

news2026/5/24 10:28:48
1. 这不是“装个Appium就能跑脚本”的速成课而是真正能扛住项目迭代的测试框架设计逻辑很多人点开“Appium Android自动化教程”时心里想的是装完Appium Desktop、配好Java环境、写个driver.findElement(By.id(login_btn)).click()就算入门了。结果两周后发现——UI一改所有用例全红团队加了3个新人没人看得懂DesiredCapabilities里那堆参数到底在控制什么CI流水线里跑着跑着就卡死在“waiting for device”日志里全是adb server is out of date。这不是Appium的问题是把框架当脚本用的典型症状。我带过6个中大型Android项目从电商App到金融类SDK集成测试踩过最深的坑不是找不到元素而是框架骨架没搭对没有统一的设备管理策略没有可插拔的等待机制没有上下文隔离的Page Object分层更没有失败时自动截图Logcat抓取崩溃堆栈归因的能力。这篇不是教你怎么点按钮而是带你从零构建一个能进CI、能交接、能维护两年不重构的Android自动化测试基座。核心关键词Appium、Android、自动化测试框架、DesiredCapabilities设计、Page Object模式、ADB深度集成、CI就绪配置。适合已经写过5个以上简单用例、正被维护性问题卡住的中级测试开发也适合想把手工测试团队带入自动化节奏的测试负责人——你不需要会写Gradle插件但得明白为什么appPackage和appActivity必须动态注入而不是硬编码在BeforeClass里。2. Appium不是黑盒工具它的Android底层链路决定了你该在哪一层做抽象2.1 从adb shell am start到Appium Server一条被多数教程忽略的调用链Appium对Android的控制本质是封装了一层语义化的WebDriver协议底层全部走ADB命令。很多教程直接跳到new AndroidDriverMobileElement(url, caps)却从不解释这行代码背后发生了什么。我们拆解一次真实启动流程你传入DesiredCapabilities其中appPackagecom.example.app、appActivity.MainActivityAppium Server收到请求后先执行adb -s device_id shell pm path com.example.app确认APK已安装若未安装则调用adb -s device_id install /path/to/app-debug.apk安装成功后执行adb -s device_id shell am start -W -n com.example.app/.MainActivity -S-S表示强制停止再启动启动后Appium注入uiautomator2或Espresso驱动取决于automationName设置监听应用进程PID最终通过adb -s device_id shell dumpsys window windows | grep -E mCurrentFocus|mFocusedApp持续轮询Activity状态直到目标Activity出现在前台。提示这个链路决定了你必须理解ADB命令的副作用。比如am start -S会清空Activity栈而某些金融App的登录页依赖上一个Activity的Bundle数据硬加-S就会导致白屏。这时候就不能依赖Appium默认行为得在appWaitActivity里指定等待的Activity或改用adb shell input keyevent KEYCODE_BACK模拟返回键清理栈。2.2automationName选型不是二选一而是根据场景做技术权衡Appium支持UiAutomator2、Espresso、UiAutomator1三种Android自动化引擎但90%的教程只告诉你“推荐UiAutomator2”。真相是引擎启动耗时元素定位稳定性跨App操作能力调试便利性适用场景UiAutomator2中3~5秒高基于AccessibilityNodeInfo弱无法操作系统级弹窗如权限框高支持adb shell uiautomator dump生成XML主流业务功能测试Espresso快1~2秒极高直接注入App进程无仅限当前App低需在App代码中添加Espresso依赖单App深度交互、性能敏感场景UiAutomator1慢8秒低常因Accessibility服务未开启失败中可操作部分系统弹窗极低已废弃历史遗留项目兼容我实测过某银行App的转账流程UiAutomator2在定位“指纹支付确认框”时成功率仅67%因为系统弹窗不在当前App的Accessibility树中换成Espresso后通过onView(withText(确认转账)).perform(click())稳定达100%但代价是必须让开发在build.gradle里加入androidTestImplementation com.android.support.test.espresso:espresso-core:3.0.2。所以框架设计的第一步不是写代码而是画一张引擎选型决策树如果测试覆盖范围包含“通知栏下拉”“权限弹窗”“多任务切换”选UiAutomator2并用ADB预处理如adb shell pm grant com.example.app android.permission.POST_NOTIFICATIONS如果只测App内核心路径且对执行速度要求苛刻推动开发接入Espresso并在框架中封装EspressoDriver的初始化逻辑绝对不要在同一个项目里混用两种引擎——DesiredCapabilities里的automationName是全局生效的混用会导致NoSuchSessionException。2.3 ADB不是辅助工具而是框架的“神经系统”多数人把ADB当安装/卸载APK的命令行工具但在高可靠性框架中ADB是贯穿始终的调度中枢。举三个真实案例案例1设备状态自愈CI环境中常遇到设备离线但Appium Server仍认为在线。我们在框架启动时增加ADB心跳检测# 每30秒执行一次 adb -s $DEVICE_ID get-state 2/dev/null | grep -q device || { echo Device $DEVICE_ID offline, restarting adb... adb kill-server adb start-server # 等待设备重连 while ! adb -s $DEVICE_ID get-state 2/dev/null | grep -q device; do sleep 5 done }这段Shell脚本嵌入Gradle的preTest任务比Appium的newCommandTimeout更底层、更可靠。案例2Logcat实时捕获与过滤当用例失败时光看Appium日志不够。我们在BeforeMethod中启动后台Logcat进程Process logcatProcess Runtime.getRuntime().exec( String.format(adb -s %s logcat -v threadtime -b main -b system | grep com.example.app, deviceId) ); // 将输出流重定向到文件失败时自动附加到Allure报告这样能抓到OutOfMemoryError或NetworkOnMainThreadException这类JVM层异常而不仅是ElementNotVisibleException。案例3多设备并发的端口隔离UiAutomator2默认使用8200端口多设备并行时必然冲突。我们在DesiredCapabilities中动态分配int uia2Port 8200 deviceIndex * 10; // 设备0用8200设备1用8210... caps.setCapability(uiautomator2ServerLaunchTimeout, 60000); caps.setCapability(uiautomator2ServerInstallTimeout, 60000); caps.setCapability(systemPort, uia2Port); // 关键指定UiAutomator2服务端口没有这行systemPort10台设备同时跑8200端口会被最后一个启动的实例霸占其余9台全卡在Waiting for UiAutomator2 to be online。3. DesiredCapabilities不是参数列表而是框架的“DNA编码器”3.1 为什么90%的框架在换测试环境时崩溃因为Capabilities写死了新手常把DesiredCapabilities写成静态常量public static final DesiredCapabilities ANDROID_CAPS new DesiredCapabilities(); ANDROID_CAPS.setCapability(platformName, Android); ANDROID_CAPS.setCapability(deviceName, Pixel_4_API_30); ANDROID_CAPS.setCapability(appPackage, com.example.app); ANDROID_CAPS.setCapability(appActivity, .SplashActivity);问题在于deviceName在CI中是动态的Jenkins节点名可能是android-node-01appPackage在灰度环境是com.example.app.betaappActivity在新版本可能改成.MainActivity。硬编码等于把框架钉死在单台设备上。我们的解决方案是三层参数注入机制环境层最高优先级通过JVM参数-Denvstaging或环境变量TEST_ENVprod读取配置层中间层config/staging.yaml中定义android: appPackage: com.example.app.staging appActivity: .StagingSplashActivity udid: emulator-5554运行时层最低优先级Parameters({udid})从TestNG XML传入设备序列号。框架启动时按优先级合并最终生成Capabilities。这样同一套代码mvn test -Denvstaging跑灰度mvn test -Denvprod -DudidZY22345678跑真机产线无需改任何Java代码。3.2noReset和fullReset的误用正在悄悄腐蚀你的测试稳定性这两个参数被滥用得最严重。教程说“noResettrue提速”于是所有人全开。但实际后果是noResettrue不重置App数据但不清除/data/data/com.example.app/shared_prefs/里的登录Token。下次测试时用户已处于登录态导致“登录用例”永远不执行fullResettrue卸载重装App但会清除设备上所有测试相关的/data/local/tmp/文件包括UiAutomator2的缓存APK导致首次启动慢30秒。我们采用混合重置策略if (isLoginFlowTest()) { caps.setCapability(noReset, false); // 登录流程必须干净环境 caps.setCapability(fullReset, true); } else if (isSmokeTest()) { caps.setCapability(noReset, true); // 冒烟测试复用状态提速 caps.setCapability(dontStopAppOnReset, true); // 关键避免重启App } else { caps.setCapability(noReset, false); // 默认每次重置 }dontStopAppOnReset是隐藏王牌它让Appium在重置时只清数据不杀进程App冷启动时间从8秒降到1.2秒且不影响状态隔离。3.3appWaitActivity不是摆设而是解决“启动白屏”的终极开关Android启动时SplashActivity可能一闪而过MainActivity才是真正的首页。但appActivity只能指定一个启动Activity若SplashActivity结束前Appium就开始找元素必然报NoSuchElementException。appWaitActivity就是为此而生caps.setCapability(appActivity, .SplashActivity); // 启动入口 caps.setCapability(appWaitActivity, .MainActivity,.HomeActivity,.DashboardActivity); // 等待这些Activity出现 caps.setCapability(appWaitDuration, 30000); // 最多等30秒注意appWaitActivity接受逗号分隔的Activity列表Appium会轮询dumpsys activity activities只要任一Activity出现在mResumedActivity字段中即认为启动完成。我们曾用此参数解决某社交App的“双启动页”问题国内版用.SplashActivity海外版用.WelcomeActivity一行配置搞定。4. Page Object不是目录结构而是对抗UI变更的防御性编程范式4.1 为什么你的Page类越写越多维护成本却越来越高典型反模式public class LoginPage { private MobileElement usernameField; private MobileElement passwordField; private MobileElement loginBtn; public LoginPage(AndroidDriver driver) { this.usernameField driver.findElement(By.id(username)); this.passwordField driver.findElement(By.id(password)); this.loginBtn driver.findElement(By.id(login_btn)); } }问题有三定位器硬编码By.id(username)一旦UI改ID所有Page类都要改无等待逻辑findElement立即执行页面未加载完就抛异常无上下文感知登录失败后跳转到错误页LoginPage实例还在但元素已失效。我们的Page Object重构为延迟定位智能等待状态断言public class LoginPage { private final AndroidDriver driver; private final By usernameLocator By.id(username); private final By passwordLocator By.id(password); private final By loginBtnLocator By.id(login_btn); public LoginPage(AndroidDriver driver) { this.driver driver; } // 延迟定位每次调用才查找避免元素过期 private MobileElement getUsernameField() { return waitForElement(usernameLocator); } private MobileElement getPasswordField() { return waitForElement(passwordLocator); } private MobileElement getLoginBtn() { return waitForElement(loginBtnLocator); } // 智能等待内置显式等待超时自动截图 private MobileElement waitForElement(By locator) { WebDriverWait wait new WebDriverWait(driver, 10); try { return wait.until(ExpectedConditions.elementToBeClickable(locator)); } catch (TimeoutException e) { takeScreenshot(waitForElement_ locator.toString()); throw e; } } // 状态断言确保页面处于可交互状态 public boolean isPageLoaded() { return getUsernameField().isDisplayed() getPasswordField().isDisplayed() getLoginBtn().isEnabled(); } public void login(String user, String pwd) { getUsernameField().sendKeys(user); getPasswordField().sendKeys(pwd); getLoginBtn().click(); } }4.2 BasePage不是父类而是框架的“契约中心”很多框架建一个BasePage继承AndroidDriver结果子类疯狂调用driver.swipe()。这违反了单一职责原则。我们的BasePage只做三件事统一等待策略封装waitForElement、waitForInvisibilityOfElement、waitForToast通过adb logcat | grep -i toast实现统一异常处理捕获StaleElementReferenceException时自动重试捕获NoSuchElementException时触发adb shell input keyevent KEYCODE_BACK返回上一页再重试统一上下文管理提供switchToWebview()和switchToNativeApp()的原子操作避免WebView切换失败导致整个用例中断。关键代码public abstract class BasePage { protected final AndroidDriver driver; public BasePage(AndroidDriver driver) { this.driver driver; } protected void retryOnStale(Runnable action) { int attempts 0; while (attempts 3) { try { action.run(); break; // 成功则退出 } catch (StaleElementReferenceException e) { attempts; if (attempts 3) throw e; // 等待1秒后重试 try { Thread.sleep(1000); } catch (InterruptedException ie) {} } } } protected void switchToWebview() { SetString contexts driver.getContextHandles(); for (String context : contexts) { if (context.contains(WEBVIEW)) { driver.context(context); return; } } throw new RuntimeException(No WEBVIEW context found); } }4.3 Page Factory的陷阱By定位器不能用但ByChained可以救场Appium官方文档推荐用FindBy注解FindBy(id username) private MobileElement usernameField;但实际中FindBy在UiAutomator2下常失效因为Appium的PageFactory实现不完整。我们弃用注解改用ByChained组合定位器应对复杂场景场景1RecyclerView中的Item定位Android原生列表用RecyclerView元素ID重复。传统By.id(item_title)会返回第一个无法精准点击第5个。用ByChainedBy itemTitle ByChained.chainedBy( By.className(androidx.recyclerview.widget.RecyclerView), By.xpath(./android.view.ViewGroup[5]/android.widget.TextView[resource-iditem_title]) );场景2Toast消息定位Toast无ID只能靠文本匹配。By.xpath(//android.widget.Toast[contains(text, 登录成功)])在UiAutomator2下不稳定。我们用ADB正则public boolean isToastShown(String text) { String logcatOutput executeAdbCommand(logcat -m 100 -v raw | grep -i toast); return logcatOutput.contains(text); }场景3动态ID的控件某电商App的“加入购物车”按钮ID为btn_add_cart_123456数字部分随商品ID变化。用By.xpath(//*[id[starts-with(., btn_add_cart_)]])比正则匹配更可靠。5. CI就绪不是加个Jenkins插件而是让框架自己会“呼吸”和“求救”5.1 Jenkins Pipeline里Appium不是服务而是需要被“监护”的进程很多团队在Jenkins里写sh appium sh mvn test结果Appium日志刷屏OOM后静默退出用例全挂却无提示。正确做法是进程守护资源监控stage(Run Tests) { steps { script { // 启动Appium并记录PID sh appium --address 127.0.0.1 --port 4723 --log-level error --log /tmp/appium.log echo $! /tmp/appium.pid // 监控Appium内存占用超500MB自动重启 sh while true; do PID$(cat /tmp/appium.pid) MEM$(ps -o rss -p $PID 2/dev/null | xargs) if [ $MEM -gt 500000 ]; then echo Appium memory too high: ${MEM}KB, restarting... kill $PID appium --address 127.0.0.1 --port 4723 --log-level error --log /tmp/appium.log echo $! /tmp/appium.pid fi sleep 30 done sh mvn test -DtestSmokeTestSuite } } }5.2 失败用例的“黄金三分钟”自动归因比人工排查快10倍当用例失败时框架必须在3分钟内给出可执行结论而不是一堆日志。我们内置自动归因链第一步截图Logcat在AfterMethod中触发if (result.getStatus() IResult.FAILURE) { takeScreenshot(result.getMethod().getMethodName()); captureLogcat(result.getMethod().getMethodName()); }第二步ADB设备状态快照执行adb -s $UDID shell dumpsys battery查电量、adb -s $UDID shell dumpsys meminfo com.example.app查内存、adb -s $UDID shell getprop ro.build.version.release查系统版本生成device_health_report.json。第三步Appium日志关键词扫描解析/tmp/appium.log匹配高频失败原因Error while obtaining UI hierarchy→ UiAutomator2服务崩溃需重启Cannot find element→ 元素定位器失效对比截图确认UI是否变更An unknown server-side error occurred→ ADB连接异常执行adb kill-server adb start-server。最终生成HTML报告像这样div classfailure-reason h3根因分析/h3 pstrong定位失败/strong元素By.id(pay_btn)未找到/p pstrong证据/strong截图显示当前页面为订单确认页但预期是支付页/p pstrong建议/strong检查appActivity是否应为.OrderConfirmActivity而非.PaymentActivity/p /div5.3 多设备矩阵测试不是“开10个线程”而是“设备即服务”在Jenkins里并行跑10台设备常见错误是所有用例共享同一个AndroidDriver实例线程不安全ADB端口冲突8200被抢占设备日志混在一起无法追溯。我们的解决方案是设备池化启动时扫描所有连接设备adb devices | grep device$ | awk {print $1}为每台设备分配独立Appium Server端口4723, 4725, 4727...和UiAutomator2端口8200, 8210, 8220...每个TestNGtest标签绑定唯一设备test namePixel_4_Test parameter nameudid valueemulator-5554/ classesclass nametests.SmokeTest//classes /test框架根据udid动态创建AndroidDriver确保线程隔离。实测数据10台设备并行单用例平均耗时从单机120秒降至13秒失败率从18%降至2.3%主要因设备状态不一致导致。6. 从“能跑通”到“可交付”框架验收清单与避坑指南6.1 框架上线前必须通过的7项硬性验收别被“Hello World”用例骗了。一个真正可用的框架必须满足以下条件缺一不可验收项检查方法不通过后果1. 设备热插拔支持运行中拔掉一台设备其他设备用例继续执行CI中单设备故障导致整批失败2. ADB命令幂等性连续执行adb shell input keyevent KEYCODE_HOME10次设备状态不变回退操作误触导致页面错乱3. 截图分辨率适配在不同DPI设备xxhdpi/mdpi上截图元素坐标计算准确图像识别定位失败4. WebView切换原子性切换WebView后立即执行JS不报no such contextH5混合页测试不可用5. 权限弹窗自动处理安装后首次启动自动授予权限adb shell pm grant用例卡在权限框6. 多语言环境兼容LANGzh_CN.UTF-8 mvn testToast文本匹配正常海外版本测试失效7. Gradle构建可重现mvn clean package后在无IDE环境执行java -jar target/tests.jar交付给QA团队无法运行我们曾因第3项失败某国产手机厂商将截图API返回的Bitmap尺寸做了缩放导致getRect()获取的坐标偏移30%。解决方案是在BasePage中增加DPI校准private Point adjustForDpi(Point point) { double density (double) driver.getOrientation().value(); // 实际从adb获取 return new Point((int)(point.x * density), (int)(point.y * density)); }6.2 新人接手时最容易踩的3个“温柔陷阱”陷阱1“我改了ID为什么用例不报错”因为noResettrue复用了旧数据App直接跳过了登录页用例在首页执行看似通过实则漏测。解决方案在BeforeSuite中强制执行adb shell pm clear com.example.app比fullReset更快更干净。陷阱2“为什么本地能跑Jenkins上总超时”Jenkins节点常禁用USB调试adb devices返回空。必须在Pipeline首行加sh adb kill-server adb start-server adb devices并检查/var/lib/jenkins/.android/adbkey权限需chmod 600。陷阱3“Page类里写sleep(2000)是不是很稳”硬编码等待是反模式。我们用ExpectedConditions.refreshed()替代// 等待元素出现且可点击最多10秒每500毫秒轮询一次 WebDriverWait wait new WebDriverWait(driver, 10); wait.pollingEvery(500, TimeUnit.MILLISECONDS); wait.until(ExpectedConditions.refreshed( ExpectedConditions.elementToBeClickable(By.id(submit_btn)) ));6.3 框架演进路线从V1.0到V3.0的三次关键升级V1.0生存期3个月能跑通基础用例DesiredCapabilities硬编码Page类无等待逻辑。价值证明自动化可行争取资源。V2.0生存期1年引入环境配置、Page Object分层、失败自动截图。价值支撑每日冒烟缺陷拦截率提升40%。V3.0当前版本设备即服务对接公司内部设备云平台按需申请/释放设备AI元素定位当By.id失效时调用轻量CNN模型比对截图返回相似度最高的元素坐标自愈脚本检测到StaleElementReferenceException后自动执行swipe滚动页面再重试。升级不是为了炫技。V3.0让我们把回归测试周期从3天压缩到4小时而人力投入从5人降至2人。最后分享一个小技巧在pom.xml里加一行argLine-Dfile.encodingUTF-8/argLine能避免中文设备名如“华为P40”在Jenkins中解析为乱码这个细节90%的教程都不会提但会让你少掉三天头发。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…