首页 文章 精选 留言 我的

精选列表

搜索[阿里云],共10000篇文章
优秀的个人博客,低调大师

浅谈测试用例设计 | 京东云技术团队

作者:京东物流王莹莹 一、测试用例为什么存在 1.1 定义 测试用例(Test Case)是指对特定的软件产品进行测试任务的描述,体现测试方案、方法、技术和策略。测试用例内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等,最终形成文档类的输出。简而言之,测试用例是为某个目标而设计的一组测试输入、执行条件以及预期结果,用于核实是否满足某个软件需求。 1.2 作用 ①指导测试(开发)的执行 测试用例作为各个测试阶段工作基准指导测试人员按照按用例项目和测试步骤实施测试。另外,测试工作左移时,测试同学提前输出的测试用例也可以指导开发人员的开发工作。 ②测试物料的准备 • 数据:按照测试用例配套准备一组或若干组测试所需的原始数据。 • 测试脚本:自动化测试脚本的设计依据。 ③测试工作进度把控 •测试工作量评估 •提高测试工作组织效率 ④测试结果的度量基准 测试完成后需要撰写测试报告,判断测试是否完成、衡量测试质量量化的结果更加准确、有效。例:测试覆盖率是多少、测试合格率是多少、重要测试合格率是多少,等等。 ⑤分析缺陷 通过测试用例和缺陷数据库对比,分析缺陷原因与类型。 二、测试用例设计基本原则 ①正确性:测试用例必须是正确的,需通过测试用例评审。 ②代表性:测试用例不可能是“穷举”的,期望在有限的测试时间内进行有效的测试,用例必须具有代表性的。 ③可判定性:用例的测试结果必须可量化,这样测试完成之后才能将测试结果与预期结果进行比较,判定是否存在BUG。 ④可重现性:测试用例执行可复现性保证问题定位的准确性。 ⑤可操作性:详细、准确和清晰的步骤是测试用例执行的必要条件,也是测试用例可重现的基础。 三、关于测试用例设计的三言两语 3.1 地基:常用测试用例设计方法(黑盒测试) 等价类划分与边界值分析 •等价类划分 将测试的范围划分成几个互不相交的子集,他们的并集是全集,从每个子集选出若干个有代表性的值作为测试用例。 •边界值分析 边界值分析法就是对输入或输出的边界值进行测试的一种方法,通常是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。 场景法 场景法是通过场景描述用例执行的路径,从用例开始到结束遍历这条路径上所有基本流和备选流。场景法适合测试业务流程清晰的系统或功能,从系统整个业务流程的全部角度对系统进行测试。 举例:京东商城购买商品,APP->选择商品->点击购买->确认购买信息->支付,这里的每个环节不同的结果结合起来都是一条不一样的用例。 错误推测法 错误猜测主要是一项依赖经验和直觉的非正规的工程方法,基本思想是列举程序可能出现的错误或者容易产生错误的测试点,然后根据测试点来编写测试用例。 举例:京东商城APP搜索输入框特殊字符的检查。 因果图与判定表 用图解的方法表示各种组合关系,写出判定表,从而设计相应的测试用例。类似于数学知识中的布尔逻辑运算,将各种输入条件的组合起来。每种组合条件就是“因”,它有一个输出的结果,这就是“果”。 举例: 正交实验法 正交试验设计是使用已经造好的正交表格进行数据分析,从中挑选出部分具有代表性的点进行试验,这些代表性的点具备了“均匀分散,整齐可比”的特点,是一种相对高效、快速的用例设计方法。 举例: 3.2 盖房子:实际工作中的测试用例设计 实际工作中,很多时候我们无法遵循理论上的测试用例设计方法那样,编写大而全的用例去执行所有大大小小需求的测试。更多情况下,用例设计时应该遵守精益测试策略,不能一味的追求测试覆盖率,有效的测试更有价值。利用测试四象限等信息指导的精益测试,追求以业务价值为目标,以尽量少的成本交付高质量的软件,做到有效覆盖,减少浪费。不管是手工测试还是自动化测试,都要先搞清楚业务价值和质量目标,测试用例设计和执行过程都需要做出相对应的考量(如测试用例的优先级)。 框架搭建 用例设计之前,我们应该熟悉需求的业务背景与技术架构,从而勾勒出测试用例整体框架。然后,使用【横向扩展】+【纵向分层】的组合模式下来针对每个需求完成用例拆解覆盖。 •横向业务扩展:指从业务角度平铺来看,总共有哪些业务场景,提供了哪些能力,即产品最上层的功能全景。 •纵向架构分层:是指从技术架构层面来分析,当前产品可以宏观上分为几层,以便于在用例验证是从不同层次上进行验证和用例覆盖。 举例: 添砖加瓦 测试框架搭建完成之后,就需要完善测试范围梳理,确认功能点的细节信息。例如,一般情况下需要进行回归测试、异常测试,再有可能需要进行并发测试、安全测试和性能测试等。从测试类型出发,结合常规用例设计方法进行用例设计与编写。 举例: 站在房子外面:像用户一样去测试 怎样像用户一样测试,能否做到还原真实用户的使用场景,还原用户在使用产品时的真实心理。说起来有点玄,但其实思路很简单。第一步想象自己就是用户,如果是我会有多少奇奇怪怪的操作或需求;第二步是弥补测试人员和用户之间的断层,用户和测试信息对齐,指导用户更好的使用软件,指导测试更有同理心。 小妙招 •用户画像:我们大概率能知道用户群体是谁,他的典型画像是什么样的,这也是我们进行换位思考的基础。 •不信任上下游:我们不能保证上下游给我的信息或者功能一定是完美的,结合自身系统定位和业务确认不同场景下我们应该做出什么样的反馈。 3.3 拓展:房子的维护,测试用例管理 测试用例是我们测试人员宝贵的财富,在测试工作中测试用例是其最为重要的基础。所以,一个良好的测试用例除了可以帮助测试人员阅读,理解,修改之外,也要方便我们去管理它,从而提高测试工作的质量和效率。不同的业务条线或者团队可以根据自己需要制定一些规则,让大家在进行测试用例设计遵守。

优秀的个人博客,低调大师

如何优雅的处理异常 | 京东云技术团队

作者:京东零售 秦浩然 一、什么是异常 Java 语言按照错误严重性,从 throwale 根类衍生出 Error 和 Exception 两大派系。 Error(错误): 程序在执行过程中所遇到的硬件或操作系统的错误。错误对程序而言是致命的,将导致程序无法运行。常见的错误有内存溢出,jvm 虚拟机自身的非正常运行,calss 文件没有主方法。程序本生是不能处理错误的,只能依靠外界干预。Error 是系统内部的错误,由 jvm 抛出,交给系统来处理。 Exception(异常): 程序正常运行中,可以预料的意外情况。比如数据库连接中断,空指针,数组下标越界。异常出现可以导致程序非正常终止,也可以预先检测,被捕获处理掉,使程序继续运行。Exception(异常)按照性质,又分为编译异常(受检异常)和运行时异常(非受检异常)。 ◦ 编译异常: 又叫可检查异常,通常时由语法错和环境因素(外部资源)造成的异常。比如输入输出异常 IOException,数据库操作 SQLException。其特点是,Java 语言强制要求捕获和处理所有非运行时异常。通过行为规范,强化程序的健壮性和安全性。 ◦ 运行时异常: 又叫不检查异常 RuntimeException,这些异常一般是由程序逻辑错误引起的,即语义错。比如算术异常,空指针异常 NullPointerException,下标越界 IndexOutOfBoundsException。运行时异常应该在程序测试期间被暴露出来,由程序员去调试,而避免捕获。 二、处理异常方式 代码中,我们最常见到的处理异常的方式就是:try-catch try { // 业务逻辑 } catch (Exception e) { // 捕获到异常的逻辑 } 或者是再进一步区分下异常类型: try { // 业务逻辑 } catch (IOException ie) { // 捕获到IO异常的逻辑 } catch (Exception e) { // 捕获到其他异常的逻辑 } 三、如何抛出异常 我们通常可以用抛出异常的方式来控制代码流程,然后在网关处统一catch异常来返回错误code。这在一定程度上可以简化代码流程控制,如下所示: @Override public UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); if (Objects.isNull(userDO)) { throw new RuntimeException("用户不存在"); //用户不存在抛出异常 } return userDO.toVo(); } 上面这种抛出异常的方式,虽然简化了代码流程,但是在存在多种错误场景时,没有办法细分具体的错误类型。如:用户不存在的错误、用户没有权限的错误; 聪明如你,一定想到了自定义异常,如下: @Override public UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); if (Objects.isNull(userDO)) { throw new UserNotFoundException(); //用户不存在抛出对应异常 } if(!checkLicence(userDO)) { throw new BadLicenceException(); //用户无权限抛出对应异常 } return userDO.toVo(); } 确实,自定义异常可以解决错误场景细分的问题。进一步的,我们可以对系统流程不同阶段、不同业务类型分别自定义异常,但这需要自定义大量的异常; 四、如何优雅的抛出异常 上面的方式,可以区分出错误场景了,但是还存在一些缺点。如:可读性差、需要定义大量的自定义异常; 那我们下面就去优化上面的问题; 用断言增加代码的可读性; @Override public UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); Assert.notNull(userDO, "用户不存在"); //用断言进行参数的非空校验 return userDO.toVo(); } 断言虽然代码简洁、可读性好,但是缺乏像上述自定义异常一样可以明确区分错误场景,这就引出我们的究极方案:自定义断言; 自定义断言; 我们用自定义断言的方式,综合上面自定义异常和断言的优点,在断言失败后,抛出我们制定好的异常。代码如下: • 自定义异常基本类 @Getter @Setter public class BaseException extends RuntimeException { // 响应码 private IResponseEnum responseEnum; // 参数信息 private Object[] objs; public BaseException(String message, IResponseEnum responseEnum, Object[] objs) { super(message); this.responseEnum = responseEnum; this.objs = objs; } public BaseException(String message, Throwable cause, IResponseEnum responseEnum, Object[] objs) { super(message, cause); this.responseEnum = responseEnum; this.objs = objs; } } • 自定义断言接口 public interface MyAssert { /** * 创建自定义异常 * * @param objs 参数信息 * @return 自定义异常 */ BaseException newException(Object... objs); /** * 创建自定义异常 * * @param msg 描述信息 * @param objs 参数信息 * @return 自定义异常 */ BaseException newException(String msg, Object... objs); /** * 创建自定义异常 * * @param t 接收验证异常 * @param msg 描述信息 * @param objs 参数信息 * @return 自定义异常 */ BaseException newException(Throwable t, String msg, Object... objs); /** * 校验非空 * * @param obj 被验证对象 */ default void assertNotNull(Object obj, Object... objs) { if (obj == null) { throw newException(objs); } } /** * 校验非空 * * @param obj 被验证对象 */ default void assertNotNull(Object obj, String msg, Object... objs) { if (obj == null) { throw newException(msg, objs); } } } 上述代码我们可以看出基本设计,就是在我们自定义断言失败后抛出我们自定义异常。 下面是具体的实现案例: • 自定义业务异常类,继承自异常基本类 public class BusinessException extends BaseException { public BusinessException(IResponseEnum responseEnum, Object[] args, String msg) { super(msg, responseEnum, args); } public BusinessException(IResponseEnum responseEnum, Object[] args, String msg, Throwable t) { super(msg, t, responseEnum, args); } } • 响应code枚举接口定义 public interface IResponseEnum { /** * 返回code码 * * @return code码 */ String getCode(); /** * 返回描述信息 * * @return 描述信息 */ String getMsg(); } • 自定义业务异常类断言定义,实现自定义断言失败后对应的自定义异常的定义; public interface BusinessExceptionAssert extends IResponseEnum, MyAssert { @Override default BaseException newException(Object... args) { return new BusinessException(this, args, this.getMsg()); //断言失败后,抛出自定义异常 } @Override default BaseException newException(String msg, Object... args) { return new BusinessException(this, args, msg); //断言失败后,抛出自定义异常 } @Override default BaseException newException(Throwable t, String msg, Object... args) { return new BusinessException(this, args, msg, t); //断言失败后,抛出自定义异常 } } • 用枚举的方式,代替BadLicenceException、UserNotFoundException自定义异常。 public enum ResponseEnum implements IResponseEnum, BusinessExceptionAssert { BAD_LICENCE("0001", "无权访问"), USER_NOT_FOUND("1001", "用户不存在"), ; private final String code, msg; ResponseEnum(String code, String msg) { this.code = code; this.msg = msg; } @Override public String getCode() { return code; } @Override public String getMsg() { return msg; } } 使用实例 自定义断言失败抛出自定义异常 @Override public UserVO queryUser(Long id) { UserDO userDO = userMapper.queryUserById(id); ResponseEnum.USER_NOT_FOUND.assertNotNull(userDO); //自定义断言失败抛出自定义异常 return userDO.toVo(); } 网关处统一catch异常,识别异常场景 public static void main(String[] args) { UserService userService = new UserServiceImpl(new UserMapperImpl()); UserController userController = new UserController(userService); try { UserVO vo = userController.queryUser(2L); //执行业务逻辑 } catch (BusinessException e) { System.out.println(e.getResponseEnum().getCode()); //出现异常,错误code:1001 System.out.println(e.getMessage()); //出现异常,错误msg:用户不存在 } } 五、如何优雅的处理异常 网关处统一处理异常,这属于常规操作,这里不再赘述,简单举例如下: @ControllerAdvice public class BusinessExceptionHandler { @ExceptionHandler(value = BusinessException.class) @ResponseBody public Response handBusinessException(BaseException e) { return new Response(e.getResponseEnum().getCode(), e.getResponseEnum().getMsg()); //统一处理异常 } } 综上,我们采用自定义断言的方式,结合了断言的可读性高的优势和自定义异常区分错误场景的优势。并且,有新增的错误场景,我们只需要在错误码枚举中新增对应枚举即可。

优秀的个人博客,低调大师

微软正在将 ChatGPT 引入 Azure 云计算服务

微软方面宣布了Azure OpenAI 服务的全面上市,这是微软对人工智能民主化的持续承诺以及与 OpenAI 持续合作的一部分。微软在 2021 年 11 月推出了 Azure OpenAI 服务,允许通过 REST API 访问 OpenAI 的强大语言模型;但彼时该服务只对有限的客户开放。 该公司 CEO萨蒂亚·纳德拉 (Satya Nadella) 发布推文称:“在我们帮助客户将世界上最先进的人工智能模型应用于他们自己的业务需要时,ChatGPT很快就会出现在 Azure OpenAI 服务中,该服务现在已经普遍可用。” 根据介绍,随着Azure OpenAI 服务的普遍可用,更多企业可以申请访问包括 GPT-3.5、Codex 和 DALL・E 2 在内的人工智能模型。用户还将能够很快通过 Azure OpenAI 服务访问 ChatGPT—— GPT-3.5 的微调版本,它已经过训练并在 Azure AI 基础设施上运行推理。 微软方面指出,Power BI 已经在使用 GPT-3 来生成公式和表达式;其还在使用 DALL•E 2 为其 Microsoft Designer AI 生成的图像提供支持。微软已经在 Azure OpenAI 服务上运行这些服务和 GitHub 的 Copilot。目前,微软已经创建了 GPT-3、DALL•E 2 和 Codex 层,具有不同的功能,分别称为Davinci、Curie、Babbage 和 Ada。其中,Davinci的能力最强,但其他的则更快。 Nadella 曾表明,微软的每一款产品都会包含一些人工智能功能。并表示:“最好的准备方式就是不要押注这项技术,这项技术可以帮助你完成工作以及你的业务流程。” 微软在 2019 年向 OpenAI 投资了 10 亿美元,作为回报,OpenAI 在追求通用人工智能的过程中在微软的 Azure AI 超级计算技术上构建了自己的 AI 模型。2020 年,微软还买下了该公司 GPT-3 语言模型的独家授权。前段时间有消息称,微软正在谈判以 290 亿美元的估值收购 OpenAI公司 100 亿美元的股份。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册