Java基础知识第九讲:单元测试、前后端规约与联调

简介: Java基础知识第九讲:单元测试、前后端规约与联调

单元测试

Action1:好的单元测试必须遵守 AIR 原则。

说明: 单元测试在线上运行时, 感觉像空气(AIR) 一样感觉不到, 但在测试质量的保障上, 却是非常关键的。 好的单元

测试宏观上来说, 具有自动化、 独立性、 可重复执行的特点。

  • A: Automatic(自动化)
  • I: Independent(独立性)
  • R: Repeatable(可重复)

Action2:单元测试应该是全自动执行的,并且非交互式的。测试用例通常是被定期执行的,执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试。不准使用 System.out 来进行人肉验证,单元测试必须使用 assert 来验证。

Action3:保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护,单元测试用例之间决不能互相调用,也不能依赖执行的先后次序。

反例:method2 需要依赖 method1 的执行,将执行结果作为 method2 的输入。

Action4:单元测试是可以重复执行的,不能受到外界环境的影响。

说明:单元测试通常会被放到持续集成中,每次有代码 push 时单元测试都会被执行。如果单测对外部环境(网络、服务、中间件等)有依赖,容易导致持续集成机制的不可用。

正例:为了不受外界环境影响,要求设计代码时就把 SUT(System under test) 的依赖改成注入,在测试时用 Spring 这样的 DI 框架注入一个本地(内存) 实现或者 Mock 实现。

Action5:对于单元测试,要保证测试粒度足够小,有助于精确定位问题。单测粒度至多是类级别,一般是方法级别。

说明:测试粒度小才能在出错时尽快定位到出错的位置。单元测试不负责检查跨类或者跨系统的交互逻辑,那是集成测试的领域。

Action6:核心业务、核心应用、核心模块的增量代码确保单元测试通过。

说明:新增代码及时补充单元测试,如果新增代码影响了原有单元测试,请及时修正。

Action7:单元测试代码必须写在如下工程目录:src/test/java,不允许写在业务代码目录下。

说明:源码编译时会跳过此目录,而单元测试框架默认是扫描此目录。

Action8:单测的基本目标:语句覆盖率达到 70%;核心模块的语句覆盖率和分支覆盖率都要达到 100%

说明:在工程规约的应用分层中提到的 DAO 层,Manager 层,可重用度高的 Service,都应该进行单元测试。

Action9:编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。

  • B:Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
  • C:Correct,正确的输入,并得到预期的结果。
  • D:Design,与设计文档相结合,来编写单元测试。
  • E:Error,强制错误信息输入(如:非法数据、异常流程、业务允许外等),并得到预期的结果。

Action10:对于数据库相关的查询,更新,删除等操作,不能假设数据库里的数据是存在的,或者直接操作数据库把数据插入进去,请使用程序插入或者导入数据的方式来准备数据。

反例:删除某一行数据的单元测试,在数据库中,先直接手动增加一行作为删除目标,但是这一行新增数据并不符合业务插入规则,导致测试结果异常。

Action11:和数据库相关的单元测试,可以设定自动回滚机制,不给数据库造成脏数据。 或者对单元测试产生的数据有明确的前后缀标识。

正例:在基础技术部的内部单元测试中,使用 FOUNDATION_UNIT_TEST_的前缀来标识单元测试相关代码。

Action12:对于不可测的代码在适当的时机做必要的重构,使代码变得可测避免为了达到测试要求而书写不规范测试代码。

Action13:在设计评审阶段,开发人员需要和测试人员一起确定单元测试范围,单元测试最好覆盖所有测试用例(UC)。

Action14:单元测试作为一种质量保障手段,在项目提测前完成单元测试,不建议项目发布后补充单元测试用例。

Action15:为了更方便地进行单元测试,业务代码应避免以下情况:

  • 构造方法中做的事情过多。
  • 存在过多的全局变量和静态方法。
  • 存在过多的外部依赖。
  • 存在过多的条件语句。

说明: 多层条件语句建议使用卫语句、 策略模式、 状态模式等方式重构。

Action16:不要对单元测试存在如下误解:

  • 那是测试同学干的事情。 本文是开发手册, 凡是本文内容都是与开发同学强相关的。
  • 单元测试代码是多余的。 系统的整体功能与各单元部件的测试正常与否是强相关的。
  • 单元测试代码不需要维护。 一年半载后, 那么单元测试几乎处于废弃状态。
  • 单元测试与线上故障没有辩证关系。 好的单元测试能够最大限度地规避线上故障

前后端规约

Action1:前后端交互的 API, 需要明确协议、 域名、 路径、 请求方法、 请求内容、 状态码、 响应体。

说明:

  • 1) 协议: 生产环境必须使用 HTTPS。
  • 2)路径: 每一个 API 需对应一个路径, 表示 API 具体的请求地址:
  • a) 代表一种资源, 只能为名词, 推荐使用复数, 不能为动词, 请求方法已经表达动作意义。
  • b) URL 路径不能使用大写, 单词如果需要分隔, 统一使用下划线。
  • c) 路径禁止携带表示请求内容类型的后缀, 比如".json", “.xml”, 通过 accept 头表达即可。
  • 3) 请求方法: 对具体操作的定义, 常见的请求方法如下:
  • a) GET:从服务器取出资源。
  • b) POST: 在服务器新建一个资源。
  • c) PUT: 在服务器更新资源。
  • d) DELETE: 从服务器删除资源。
  • 4) 请求内容: URL 带的参数必须无敏感信息或符合安全要求; body 里带参数时必须设置 Content-Type。
  • 5) 响应体: 响应体 body 可放置多种数据类型, 由 Content-Type 头来确定。

Action2:前后端数据列表相关的接口返回, 如果为空, 则返回空数组[]或空集合{}。

  • 说明: 此条约定有利于数据层面上的协作更加高效, 减少前端很多琐碎的 null 判断。

Action3:服务端发生错误时,返回给前端的响应信息必须包含 HTTP 状态码,errorCode、errorMessage、 用户提示信息四个部分。

说明: 四个部分的涉众对象分别是浏览器、 前端开发、 错误排查人员、 用户。其中输出给用户的提示信息要求: 简短清

晰、 提示友好, 引导用户进行下一步操作或解释错误原因, 提示信息可以包括错误原因、 上下文环境、 推荐操作等。

  • errorCode: 参考 。
  • errorMessage:简要描述后端出错原因,便于错误排查人员快速定位问题,注意不要包含敏感数据信息。

正例: 常见的 HTTP 状态码如下

  • 1) 200 OK: 表明该请求被成功地完成,所请求的资源发送到客户端。
  • 2) 401 Unauthorized: 请求要求身份验证,常见对于需要登录而用户未登录的情况。
  • 3) 403 Forbidden:服务器拒绝请求,常见于机密信息或复制其它登录用户链接访问服务器的情况。
  • 4) 404 NotFound: 服务器无法取得所请求的网页,请求资源不存在。
  • 5) 500 InternalServerError:服务器内部错误。

Action4:在前后端交互的 JSON 格式数据中, 所有的 key 必须为小写字母开始的 lowerCamelCase

风格, 符合英文表达习惯, 且表意完整。

正例: errorCode / errorMessage / assetStatus / menuList / orderList / configFlag

反例: ERRORCODE / ERROR_CODE / error_message / error-message / errormessage

Action5:errorMessage 是前后端错误追踪机制的体现, 可以在前端输出到 type=“hidden” 文字类控件中, 或者用户端的日志中, 帮助我们快速地定位出问题。

Action6:对于需要使用超大整数的场景, 服务端一律使用 String 字符串类型返回, 禁止使用 Long 类型。

说明: Java 服务端如果直接返回 Long 整型数据给前端, Javascript 会自动转换为 Number 类型(注: 此类型为双精度浮点数, 表示原理与取值范围等同于 Java 中的 Double)。 Long 类型能表示的最大值是 2^ 63 -1, 在取值范围之内, 超过 2^ 53(9007199254740992) 的数值转化为 Javascript 的 Number 时, 有些数值会产生精度损失。

扩展说明,:在 Long 取值范围内, 任何 2 的指数次的整数都是绝对不会存在精度损失的, 所以说精度损失是一个概率问题。 若浮点数尾数位与指数位空间不限, 则可以精确表示任何整数, 但很不幸, 双精度浮点数的尾数位只有 52 位。

  • 反例: 通常在订单号或交易号大于等于 16 位, 大概率会出现前后端订单数据不一致的情况。
  • 比如, 后端传输的 “orderId”: 362909601374617692, 前端拿到的值却是: 362909601374617660

Action7:HTTP 请求通过 URL 传递参数时,不能超过 2048 字节。

说明: 不同浏览器对于 URL 的最大长度限制略有不同, 并且对超出最大长度的处理逻辑也有差异, 2048 字节是取所

有浏览器的最小值。

反例: 某业务将退货的商品 id 列表放在 URL 中作为参数传递, 当一次退货商品数量过多时, URL 参数超长, 传递到后端的

参数被截断, 导致部分商品未能正确退货。

Action8:HTTP 请求通过 body 传递内容时,必须控制长度,超出最大长度后,后端解析会出错。

说明: nginx 默认限制是 1MB, tomcat 默认限制为 2MB, 当确实有业务需要传较大内容时, 可以调大服务器端的限制。

Action9:在翻页场景中, 用户输入参数的小于 1, 则前端返回第一页参数给后端;

  • 后端发现用户输入的参数大于总页数,直接返回最后一页。

Action10:服务器内部重定向必须使用 forward; 外部重定向地址必须使用 URL 统一代理模块生成, 否则会因线上采用 HTTPS 协议而导致浏览器提示“不安全” ,并且还会带来 URL 维护不一致的问题。

Action11:服务器返回信息必须被标记是否可以缓存,如果缓存,客户端可能会重用之前的请求结果。

说明: 缓存有利于减少交互次数, 减少交互的平均延迟。

正例: http1.1 中, s-maxage 告诉服务器进行缓存,时间单位为秒,用法如下,response.setHeader("Cache-Control", "s-maxage=" + cacheSeconds);

Action12:服务端返回的数据, 使用 JSON 格式而非 XML。

说明: 尽管 HTTP 支持使用不同的输出格式, 例如纯文本, JSON, CSV, XML, RSS 甚至 HTML。如果我们使用的面

向用户的服务, 应该选择 JSON 作为通信中使用的标准数据交换格式, 包括请求和响应。此外, application/JSON 是

一种通用的 MIME 类型, 具有实用、 精简、 易读的特点。

Action13:前后端的时间格式统一为"yyyy-MM-dd HH:mm:ss", 统一为 GMT。

Action14:在接口路径中不要加入版本号, 版本控制在 HTTP 头信息中体现, 有利于向前兼容。

说明: 当用户在低版本与高版本之间反复切换工作时, 会导致迁移复杂度升高, 存在数据错乱风险。

相关文章
|
1月前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
227 2
|
2月前
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
47 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
|
2月前
|
Java 程序员 测试技术
Java|让 JUnit4 测试类自动注入 logger 和被测 Service
本文介绍如何通过自定义 IDEA 的 JUnit4 Test Class 模板,实现生成测试类时自动注入 logger 和被测 Service。
35 5
|
2月前
|
存储 人工智能 Java
将 Spring AI 与 LLM 结合使用以生成 Java 测试
AIDocumentLibraryChat 项目通过 GitHub URL 为指定的 Java 类生成测试代码,支持 granite-code 和 deepseek-coder-v2 模型。项目包括控制器、服务和配置,能处理源代码解析、依赖加载及测试代码生成,旨在评估 LLM 对开发测试的支持能力。
56 1
|
2月前
|
分布式计算 Java 大数据
大数据-122 - Flink Time Watermark Java代码测试实现Tumbling Window
大数据-122 - Flink Time Watermark Java代码测试实现Tumbling Window
45 0
|
3月前
|
SQL JavaScript 前端开发
基于Java访问Hive的JUnit5测试代码实现
根据《用Java、Python来开发Hive应用》一文,建立了使用Java、来开发Hive应用的方法,产生的代码如下
82 6
|
2月前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
39 0
|
4月前
|
IDE Java 测试技术
揭秘Java高效编程:测试与调试实战策略,让你代码质量飞跃,职场竞争力飙升!
【8月更文挑战第30天】在软件开发中,测试与调试对确保代码质量至关重要。本文通过对比单元测试、集成测试、调试技巧及静态代码分析,探讨了多种实用的Java测试与调试策略。JUnit和Mockito分别用于单元测试与集成测试,有助于提前发现错误并提高代码可维护性;Eclipse和IntelliJ IDEA内置调试器则能快速定位问题;Checkstyle和PMD等工具则通过静态代码分析发现潜在问题。综合运用这些策略,可显著提升代码质量,为项目成功打下坚实基础。
69 2
|
4月前
|
XML Java 测试技术
Selenium WebDriver自动化测试(基础篇):不得不掌握的Java基础
关于Selenium WebDriver自动化测试的Java基础篇,涵盖了Java的变量、数据类型、字符串操作、运算符、流程控制、面向对象编程、关键字用法、权限修饰符、异常处理和IO流等基础知识点,为进行自动化测试提供了必要的Java语言基础。
121 1
|
4月前
|
Java 测试技术 API
Java 新手入门:Java单元测试利器,Mock详解
Java 新手入门:Java单元测试利器,Mock详解
264 1