Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
如何测试内部捕获的异常_创想鸟

如何测试内部捕获的异常

如何测试内部捕获的异常

本文深入探讨了在单元测试中如何处理和验证被内部捕获的异常。当方法内部抛出异常但随即被 `try-catch` 块捕获并处理(例如仅记录日志)时,传统的 `assertThrows` 机制将无法直接验证。文章分析了这种设计模式带来的测试挑战,并提供了两种主要解决方案:首先是推荐通过重构代码以提高可测试性,例如使用 `Optional` 或自定义结果对象来明确指示操作结果;其次是针对无法立即重构的现有代码,探讨了通过验证日志输出或利用 `fail()` 方法来间接测试异常处理逻辑的策略。

理解问题:内部捕获异常的测试挑战

软件开发中,我们经常会遇到方法内部抛出异常,但这些异常被随后的 try-catch 块捕获并处理的情况。例如,异常可能被记录下来,但不会重新抛出或以其他方式向上层调用者传递。这种设计模式给单元测试带来了挑战,因为标准的 assertThrows 断言机制只能检测到从被测试方法中 抛出 的异常,而无法感知在方法内部被捕获的异常。

考虑以下示例代码:

Class A (调用者)

public class A {    private static Logger logger = LoggerFactory.getLogger("A");    private B b;    public A() {        b = new B();    }    public void methodA() {        b.methodB();        logger.info("A");    }}

Class B (被调用者,内部抛出并捕获异常)

import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class B {    private static Logger logger = LoggerFactory.getLogger("B");    public B() {        // 通常logger在构造函数中初始化一次    }    public void methodB() {        try {            // 模拟一个内部异常            throw new Exception("NULL");        } catch(Exception e) {            // 异常被捕获并记录,但未重新抛出            logger.info("Exception thrown internally in B", e);        }    }}

当尝试使用 assertThrows 来测试 Class B 内部抛出的异常时,会遇到问题:

错误的测试示例

import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertThrows;public class ATest { // 假设这是测试 A 或 B 的类    @Test    public void testExceptionInB() {        B b = new B();        // 尝试断言 b.methodB() 抛出异常,但它内部已经捕获了        assertThrows(Exception.class, () -> b.methodB());    }}

执行上述测试会得到如下错误:

Expected java.lang.Exception to be thrown, but nothing was thrown.org.opentest4j.AssertionFailedError: Expected java.lang.Exception to be thrown, but nothing was thrown.

这正是因为 methodB 中的 catch 块已经处理了异常,使得 methodB 方法本身正常完成,没有向外抛出任何异常。

核心问题:异常处理设计缺陷

上述 Class B 的设计模式,即在内部捕获并“吞噬”异常而不向调用者提供任何明确反馈,通常被认为是一种不良实践。这种设计存在以下几个问题:

可测试性差:如上所示,难以直接验证内部异常的发生。错误信息丢失:调用者无法得知操作是否失败以及失败的具体原因。调试困难:当系统行为异常时,由于错误信息被内部消化,定位问题变得更加复杂。违反“命令-查询分离”原则:一个方法在执行某个命令时,应该通过返回值或异常明确其结果。

理想情况下,异常应该在能够处理它们的层次被捕获。如果一个方法无法完全处理异常,它应该重新抛出(可能封装为更具体的业务异常),或者通过返回值明确指示失败状态。

推荐方案:重构以提高可测试性

解决内部捕获异常测试问题的最佳方法是重构代码,使其遵循更好的异常处理实践,从而自然地提高可测试性。

方案一:返回 Optional 或自定义结果对象

如果一个操作可能失败但又不想强制调用者处理异常(例如,操作失败不认为是“异常”情况,而是一种预期结果),可以使用 Optional 或自定义结果对象来明确表示操作的成功或失败,并携带相关信息。

企业网站通用源码1.0 企业网站通用源码1.0

企业网站通用源码是以aspcms作为核心进行开发的asp企业网站源码。企业网站通用源码是一套界面设计非常漂亮的企业网站源码,是2016年下半年的又一力作,适合大部分的企业在制作网站是参考或使用,源码亲测完整可用,没有任何功能限制,程序内核使用的是aspcms,如果有不懂的地方或者有不会用的地方可以搜索aspcms的相关技术问题来解决。网站UI虽然不是特别细腻,但是网站整体格调非常立体,尤其是通观全

企业网站通用源码1.0 0 查看详情 企业网站通用源码1.0

Class B 重构示例 (使用 Optional)

import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.Optional;public class BRefactored {    private static Logger logger = LoggerFactory.getLogger("BRefactored");    public BRefactored() {        // 构造函数逻辑    }    /**     * 执行操作并返回一个Optional,指示操作是否成功。     * 如果操作失败,Optional为空,并记录错误。     * @return 如果操作成功,返回一个非空的Optional;否则返回Optional.empty()。     */    public Optional methodB() {        try {            // 模拟一个内部异常            throw new Exception("Simulated internal error");            // 假设这里是成功路径,返回一些数据            // return Optional.of("Operation successful");        } catch(Exception e) {            logger.error("Exception thrown internally in BRefactored: {}", e.getMessage());            // 明确表示操作失败            return Optional.empty();        }    }}

Class A 相应修改示例

import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.Optional;public class AModified {    private static Logger logger = LoggerFactory.getLogger("AModified");    private BRefactored bRefactored;    public AModified() {        bRefactored = new BRefactored();    }    public void methodA() {        Optional result = bRefactored.methodB();        if (result.isPresent()) {            logger.info("B operation successful: {}", result.get());        } else {            logger.warn("B operation failed, handling gracefully in A.");        }        logger.info("A");    }}

重构后 Class B 的测试示例现在,可以直接测试 methodB 的返回值来判断内部操作是否成功或失败:

import org.junit.jupiter.api.Test;import java.util.Optional;import static org.junit.jupiter.api.Assertions.*;public class BRefactoredTest {    @Test    void testMethodB_failureScenario() {        BRefactored b = new BRefactored();        Optional result = b.methodB();        // 断言Optional为空,表示操作失败        assertTrue(result.isEmpty(), "methodB should return empty Optional on failure");    }    // 如果有成功路径,可以这样测试    // @Test    // void testMethodB_successScenario() {    //     BRefactored b = new BRefactored();    //     Optional result = b.methodB();    //     assertTrue(result.isPresent(), "methodB should return non-empty Optional on success");    //     assertEquals("Operation successful", result.get());    // }}

方案二:重新抛出特定异常

如果内部异常代表了一个调用者应该知道并可能需要处理的错误情况,那么应该捕获原始异常并重新抛出封装后的、更具业务含义的异常。

Class B 重构示例 (重新抛出业务异常)

import org.slf4j.Logger;import org.slf4j.LoggerFactory;// 自定义业务异常class BusinessOperationException extends RuntimeException {    public BusinessOperationException(String message, Throwable cause) {        super(message, cause);    }}public class BRefactoredThrows {    private static Logger logger = LoggerFactory.getLogger("BRefactoredThrows");    public BRefactoredThrows() {        // 构造函数逻辑    }    /**     * 执行操作。如果内部发生错误,则抛出 BusinessOperationException。     * @throws BusinessOperationException 如果内部操作失败。     */    public void methodB() {        try {            // 模拟一个内部异常            throw new IllegalStateException("Critical internal state error");        } catch(Exception e) {            logger.error("Exception caught internally, rethrowing as BusinessOperationException: {}", e.getMessage());            // 捕获原始异常,封装并重新抛出            throw new BusinessOperationException("Failed to perform B operation", e);        }    }}

重构后 Class B 的测试示例现在可以使用 assertThrows 直接测试 methodB 抛出的业务异常:

import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertThrows;import static org.junit.jupiter.api.Assertions.assertTrue;public class BRefactoredThrowsTest {    @Test    void testMethodB_throwsBusinessOperationException() {        BRefactoredThrows b = new BRefactoredThrows();        // 断言 methodB 抛出 BusinessOperationException        BusinessOperationException thrown = assertThrows(            BusinessOperationException.class,            () -> b.methodB(),            "methodB should throw BusinessOperationException"        );        // 进一步验证异常信息或原因        assertTrue(thrown.getMessage().contains("Failed to perform B operation"));        assertTrue(thrown.getCause() instanceof IllegalStateException);    }}

替代方案:测试现有“坏设计”代码 (非理想但有时必要)

在某些情况下,我们可能无法立即重构现有代码,但仍需要为其编写测试。对于内部捕获并记录日志的异常,可以采用以下非理想但有时实用的测试策略。

方案一:验证日志输出

如果异常被捕获后会记录日志,那么可以通过验证日志系统是否接收到预期的错误消息来间接确认异常的发生。这通常需要一些额外的设置来捕获和检查日志。

概念性实现思路:

使用测试日志 Appender/Listener:许多日志框架(如 Logback, Log4j2)允许在测试环境中配置一个特殊的 Appender,它可以捕获日志事件并将其存储在内存中,供测试断言使用。模拟 Logger:使用 Mockito 等工具模拟 Logger 实例。如果 Logger 是通过依赖注入或可在测试中替换的方式获取的,可以模拟它来验证 error() 或 warn() 方法是否被调用,以及调用时传入的参数是否符合预期。

示例 (使用 Mockito 模拟 Logger)假设 Class B 可以通过构造函数注入 Logger:

import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class BInjectableLogger {    private final Logger logger;    public BInjectableLogger(Logger logger) {        this.logger = logger;    }    public void methodB() {        try {            throw new Exception("NULL");        } catch(Exception e) {            logger.info("Exception thrown internally in BInjectableLogger", e);        }    }}

测试示例

import org.junit.jupiter.api.Test;import org.mockito.ArgumentCaptor;import org.slf4j.Logger;import static org.mockito.Mockito.*;import static org.junit.jupiter.api.Assertions.assertTrue;public class BInjectableLoggerTest {    @Test    void testMethodB_logsException() {        // 创建一个模拟的Logger        Logger mockLogger = mock(Logger.class);        BInjectableLogger b = new BInjectableLogger(mockLogger);        b.methodB();        // 验证logger.info方法是否被调用        // 捕获传递给info方法的参数        ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(String.class);        ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class);        // 验证info方法至少被调用一次,并捕获参数        verify(mockLogger, times(1)).info(messageCaptor.capture(), throwableCaptor.capture());        // 断言日志消息和捕获的异常类型        assertTrue(messageCaptor.getValue().contains("Exception thrown internally"));        assertTrue(throwableCaptor.getValue() instanceof Exception);        assertTrue(throwableCaptor.getValue().getMessage().contains("NULL"));    }}

注意事项:如果 Logger 是通过 LoggerFactory.getLogger() 静态获取的,直接模拟会比较困难,可能需要 PowerMock 等工具,或者使用日志框架提供的测试工具。

方案二:使用 fail() 确保异常被捕获(基于原答案)

这种方法的目标是确保异常 确实被捕获没有逃逸 到调用的上层。如果 methodB 的 try-catch 块未能捕获到异常(例如,异常类型不匹配或 try 块逻辑改变导致异常在 catch 块外部抛出),那么测试将失败。

测试示例

import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.fail; // 导入 failpublic class ATestOriginalDesign {    @Test    void testMethodB_exceptionIsSwallowed() {        B b = new B(); // 使用原始的Class B        try {            b.methodB();            // 如果 methodB 内部的异常被成功捕获并处理,            // 那么代码会执行到这里,表示异常没有逃逸。            // 此时,我们不希望测试失败,所以这里不需要 fail()。            // 如果测试的目的是确保它 *不会* 抛出异常到外部,则此路径表示成功。            // 如果测试的目的是确保它 *内部* 抛出了异常,这种方法并不能直接验证。        } catch (Exception e) {            // 如果 methodB 内部的 catch 块没有捕获异常,            // 异常就会逃逸到这里,导致测试失败。            fail("Exception was not swallowed by B.methodB(): " + e.getMessage());        }    }    // 另一种更符合原答案意图的场景:    // 如果我们想测试一个方法,它 *应该* 捕获并处理某个异常,    // 但万一它没处理,我们就让测试失败。    @Test    void testMethodB_ensuresNoUnhandledExceptionEscapes() {        B b = new B(); // 原始的 Class B        try {            b.methodB();            // 如果代码执行到这里,说明 methodB 成功处理了内部异常,没有向外抛出。            // 对于一个“吞噬”异常的设计,这正是我们期望的行为,所以测试通过。        } catch (Exception e) {            // 如果 methodB 没有捕获异常,异常就会逃逸到这里。            // 此时,我们认为这是一个失败情况,因为 methodB 的设计目标是捕获它。            fail("Expected B.methodB() to swallow its internal exception, but it escaped: " + e.getMessage());        }    }}

此方法的局限性:这种方法实际上是在测试“异常没有逃逸”,而不是直接验证“内部抛出了异常”。对于 Class B 这种 总是 捕获异常的设计,testMethodB_ensuresNoUnhandledExceptionEscapes 这样的测试会 总是通过,因为它只是验证了 methodB 的 catch 块功能正常。它无法直接

以上就是如何测试内部捕获的异常的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1073239.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
pubmed官网权威主页页_pubmed生物医学文献查询官网
上一篇 2025年12月2日 06:56:16
css定位在弹性盒子布局中的使用方法
下一篇 2025年12月2日 06:56:19

相关推荐

  • windows10如何查看S.M.A.R.T.硬盘状态_windows10硬盘S.M.A.R.T.状态查看方法

    电脑运行慢、蓝屏或文件损坏可能是硬盘故障前兆,可通过S.M.A.R.T.技术检测健康状况。1、使用WMIC命令行工具输入“wmic diskdrive get model,status”查看状态,显示Pred Fail需立即备份数据;2、CrystalDiskInfo可深度分析S.M.A.R.T.参…

    2026年9月21日
    100
  • Photopea的AI功能怎么裁剪图片?快速实现高效图片裁剪技巧

    Photopea的AI功能怎么裁剪图片?快速实现高效图片裁剪技巧Photopea的AI功能怎么裁剪图片?快速实现高效图片裁剪技巧Photopea的AI功能怎么裁剪图片?快速实现高效图片裁剪技巧Photopea的AI功能怎么裁剪图片?快速实现高效图片裁剪技巧

    Photopea的AI功能通过智能选择工具与内容感知技术结合,实现高效图片裁剪。首先使用对象选择、快速选择或魔棒工具智能识别主体或背景,再通过“选择并遮住”精细调整边缘,尤其适用于复杂轮廓如发丝。随后可应用图层蒙版透明化背景,并用裁剪工具调整画布范围。结合内容感知填充可移除干扰元素并自动补全画面,内…

    2026年9月21日 用户投稿
    300
  • Sublime开发MySQL存储过程教程实战_封装重复逻辑减少前端负担

    Sublime开发MySQL存储过程教程实战_封装重复逻辑减少前端负担Sublime开发MySQL存储过程教程实战_封装重复逻辑减少前端负担Sublime开发MySQL存储过程教程实战_封装重复逻辑减少前端负担Sublime开发MySQL存储过程教程实战_封装重复逻辑减少前端负担

    在web开发中使用mysql存储过程能有效封装逻辑并减少前端负担,本文介绍了其优势、环境配置及实战技巧。一、存储过程的优势包括减少网络传输、提高性能、统一业务逻辑;二、sublime text配置步骤为安装package control、sublimerepl插件、sql语法高亮插件,并建议新建.s…

    2026年9月21日 用户投稿
    800
  • Linux中如何安装Redis_Linux安装Redis服务的完整教程

    安装编译环境和依赖:Ubuntu/Debian用apt安装build-essential tcl wget,CentOS/RHEL用yum安装Development Tools和tcl wget。2. 下载Redis 7.2.4源码包并%ignore_a_1%,进入目录后执行make编译,可选mak…

    2026年9月21日
    000
  • 小红书从哪里看私信记录?私信记录如何清理?

    在小红书上与朋友或喜欢的博主互动时,私信是必不可少的沟通方式。不少新手用户常常困惑于如何查找过往的聊天内容。本文将为你详细说明查看私信记录的具体步骤,并分享几种实用的清理方法,帮助你轻松管理私信箱,让对话界面更清爽。 一、如何找到小红书的私信记录? 查看私信的操作非常直观,只需几个简单步骤即可完成。…

    2026年9月21日
    000
  • PHP框架中间件有什么用处_PHP框架中间件设计与实现

    PHP框架中间件是处理请求和响应的过滤器,用于实现身份验证、日志记录、CORS等通用逻辑,核心价值在于解耦和提升可维护性。通过定义中间件接口、具体中间件类及管道调度器可实现自定义中间件,如身份验证或CORS处理。在Laravel中可通过Kernel.php配置全局、分组或路由级中间件,执行顺序按注册…

    2026年9月21日
    000
  • Java中字符到数字转换:解决for循环提前返回的常见陷阱

    本文探讨java中`for`循环在字符到数字转换时,因`return`语句放置不当导致程序提前终止、无法完整处理字符串的问题。我们将分析这种常见陷阱,并提供修正方案,演示如何正确利用循环填充数组,并在循环结束后统一返回最终结果,确保每个字符都能被准确映射和组合。 引言:字符到数字的映射需求 在编程实…

    2026年9月21日
    000
  • Linux如何查看网络带宽使用情况

    使用iftop实时查看网络连接带宽,nethogs按进程监控流量,sar查看历史网络统计,vnstat记录长期流量,四者分别适用于实时监控、进程定位、短期统计和长期分析。 在Linux系统中,查看网络带宽使用情况有多种方法,可以通过命令行工具实时监控网络流量和带宽占用。以下是几种常用且实用的方式。 …

    2026年9月21日
    100
  • 系统界面美化的10个方法

    采用一致色彩方案,使用协调主色调并保持元素颜色统一;2. 选用清晰字体如思源黑体,规范字号层级;3. 增加留白提升视觉舒适度;4. 统一图标风格并使用SVG格式;5. 添加微动效增强交互引导;6. 采用卡片式布局与栅格系统;7. 支持深浅色模式切换并优化对比度;8. 精简装饰元素突出核心功能;9. …

    2026年9月21日
    200
  • win10登录界面不显示用户头像或名称怎么办_恢复登录界面完整显示的操作方法

    登录界面缺少头像或账户名时,先检查账户名一致性,修复头像缓存,重设头像,扫描系统文件,必要时创建新管理员账户验证问题。 如果您在启动Windows 10后,登录界面仅显示密码输入框而缺少用户头像或账户名称,则可能是由于系统设置、缓存异常或账户配置问题导致。以下是恢复登录界面完整显示的详细操作方法。 …

    2026年9月21日
    100
  • word怎么设置页边距_word文档页边距设置步骤

    首先打开Word文档,点击“布局”选项卡中的“页边距”按钮,可选择预设值或点击“自定义页边距”进行详细设置,输入上下左右边距及装订线数值,再通过“应用于”选择范围,最后点击“确定”完成设置。 在使用Word编辑文档时,设置合适的页边距能让内容排版更美观,也符合打印或提交要求。下面介绍如何在Word中…

    2026年9月21日
    000
  • 小红书合规引流全套方案2025:6招实现私域用户300%增长的实用技巧

    内容为王,精准定位:围绕目标用户画像创作高质量、垂直领域的原创内容,如教程攻略、真实好物推荐、生活分享与避坑指南,形式涵盖图文、短视频与直播,以解决用户实际问题为核心;2. 巧妙互动,建立连接:积极回复评论与私信,发起话题活动与抽奖提升参与感,并通过创建社群增强用户粘性,始终以真诚态度提供价值;3.…

    2026年9月21日
    000
  • 梦幻号虚拟主播电商运营宝典(附新手教程+配套工具清单)

    虚拟主播电商的核心在于“内容驱动销售,人设凝聚用户”,要让“梦幻号”真正动起来并实现带货,必须先赋予其鲜明的人设,包括清晰的定位标签(如美食家、科技宅)、独特的人格魅力(性格、口头禅、小缺点)和与产品的强关联性,使其具备辨识度和故事感,从而建立用户信任;接着通过obs studio、vtube st…

    2026年9月21日
    000
  • win10平板模式下屏幕键盘不自动弹出怎么办_恢复屏幕键盘自动弹出的技巧

    1、检查平板电脑模式设置,确保登录和使用时均启用平板模式并重启;2、在设备→输入中开启“不处于平板模式且未连接键盘时显示触摸键盘”;3、通过注册表编辑器创建InitialKeyboardIndicators值为2(十六进制)以强制启用键盘指示器;4、手动显示触摸键盘按钮并测试各应用兼容性,排查特定软…

    2026年9月21日
    000
  • deepseek下载速度优化_从deepseek下载速度优化官网获取

    deepseek下载速度优化入口在官网https://www.deepseek.com,进入后可通过设置调整响应模式、使用智能路由和数据压缩技术提升速度。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ deepseek下载速度优化入口地址在…

    2026年9月21日
    000
  • Linux如何设置目录的执行权限

    目录的执行权限是访问其内容的“钥匙”,使用chmod命令可通过符号或八进制模式设置,常见权限为755(所有者rwx,组和其他用户rx),递归设置时推荐结合find命令分别处理文件和目录,避免误加执行权限。 在Linux中,设置目录的执行权限( x )并非意味着你可以“运行”这个目录,而是赋予了你进入…

    2026年9月21日
    000
  • 纯白颜值、双模切换:“纯白小金刚”技嘉M27UP ICE显示器登场

    纯白颜值、双模切换:“纯白小金刚”技嘉M27UP ICE显示器登场纯白颜值、双模切换:“纯白小金刚”技嘉M27UP ICE显示器登场纯白颜值、双模切换:“纯白小金刚”技嘉M27UP ICE显示器登场纯白颜值、双模切换:“纯白小金刚”技嘉M27UP ICE显示器登场

    在电竞DIY领域深耕多年的技嘉,始终致力于满足玩家对高颜值与个性化外设的追求。为助力用户打造一体化的纯白主题电竞空间,品牌全新推出了专为此场景设计的M27UP ICE显示器。这款产品定位于两千元左右价位,凭借出众的纯白外观、卓越性能与超高性价比,被玩家们亲切称为“纯白小金刚”。如果你正想入手一台兼具…

    2026年9月21日 用户投稿
    000
  • Java多线程API调用中Future.get()返回null的解决方案

    本文旨在解决%ignore_a_1%api调用中`future.get()`方法返回`null`的常见问题。当使用`callable`和`executorservice`并发执行api请求并尝试获取结果时,如果流读取逻辑不当,可能导致获取到的数据为空。文章将详细解释问题根源,并提供使用`string…

    2026年9月21日
    000
  • VSCode的自动保存功能如何开启?

    在VSCode中开启自动保存需进入“文件”→“首选项”→“设置”,搜索auto save并选择Files: Auto Save模式,可选afterDelay、onFocusChange或onWindowChange,其中afterDelay可设置延迟时间如1000毫秒,启用后状态栏显示保存状态以确认…

    2026年9月21日
    000
  • 交管12123处理非本人车辆违章怎么办_交管12123处理非本人车辆违章攻略

    可通过“交管12123”APP处理非本人名下车辆的交通违法,但需先完成备案。备案方式有两种:一是扫码备案,由车主生成二维码后驾驶人扫描并提交信息;二是短信验证备案,输入车牌号、发动机号后六位,系统向车主手机发送验证码,输入后完成备案。备案成功后,进入APP【更多】→【违法处理】,选择已备案车辆,查看…

    2026年9月21日
    000

发表回复

登录后才能评论
关注微信