第33周JavaSpringCloud微服务 多人协作下的调试
第33周JavaSpringCloud微服务 多人协作下的调试
一、多人协作下的测试的不同
在多人开发场景下,测试工作需要进行相应调整,因为依赖他人接口与自主开发存在显著差异。
1.1 依赖他人接口的挑战
- 已完成开发的接口 :若对方已完成开发,调用其接口可视为成功,但前提是对方服务已启动、开发完成并部署至稳定的测试环境。然而,常出现对方接口数据错误或测试环境故障,此时需联系对方修复,沟通成本高且受制于人。
- 并行开发的任务 :在并行开发大任务时,任务被拆分为不同部分,开发进度不一。当所依赖的部分仅提供基本接口文档或仅告知最终返回内容时,无法直接进行依赖。此时,并非无法继续开发,而是需采用特定技术应对。
1.2 解决方案:引入Mock技术
Mock技术可以模拟接口的返回内容,使得开发工作可以继续进行,而不必等待依赖方完成接口开发。
- Mock的含义 :Mock是指模拟、假装的意思。具体来说,它表示接口不是真正的调用,而是提前约定的返回内容,仅用于开发联调。在真正上线时,需要去掉这些Mock内容。
- 多人调试 :多人调试指的是程序员调试他人代码的过程,主要包含以下两种情况:
- 他人代码以库或依赖的形式存在 :此时,可通过Maven引入,直接在相应代码上打断点。当执行到该位置时,IDE会自动停止,从而进行调试。这种方式类似于半本地调试,与调试自己编写的代码差别不大,主要区别在于代码来源。
- 需调试的代码运行在他人服务器上 :如调用他人的HTTP接口。此时,无法直接查看接口内部执行过程或打断点,因为对于调试者来说,这是一个黑盒,仅知道最终返回结果。在这种情况下,可能依赖对方HTTP请求的返回进行调试。例如,希望改变对方接口的返回值,以观察程序在不同返回值下的表现,确保程序能正确处理各种返回情况。
二、Mockito介绍
Mockito是一个广泛使用的模拟框架,其API(接口)及使用方法相对简单,且功能强大。
2.1 创建测试类
- 引入依赖 :在POM文件中引入Mockito依赖。
- 创建测试类 :在编写测试类时,首先定位到相应的方法。创建测试类后,需进行部分调整:删除自动生成的内容,并添加两个注解。第一个注解为
@RunWith
,在其中指定MockitoJUnitRunner.class
;第二个注解为@SpringBootTest
。接着,将类修改为public
。之后,在类中编写与Mockito相关的内容。
2.2 创建Mock对象
- 方法一 :使用Mockito框架的
mock
方法,传入一个类,以便对其进行模拟。然后,使用when
方法对mock对象的行为进行模拟。 - 方法二 :使用注解的形式进行Mock和Spy。注解
@Mock
用于创建Mock对象,注解@Spy
用于创建Spy对象。
三、单元测试实操
3.1 平常的单元测试
- 测试update方法 :新建一个方法
public void testUpdateInformation
,用于测试update方法,该方法用于更新个人信息,并加上@Transactional
注解。在测试中无需对数据库内容做真正修改,测试会自动识别并在完成测试后回滚操作。 - 编写单元测试 :创建一个User对象,设置其ID和新的个性签名。调用update方法更新该User对象的个性签名。使用UserMapper的
selectByPrimaryKey
方法,根据主键ID查询更新后的User对象。比较查询到的User对象的个性签名与设置的个性签名是否一致,若一致则测试通过。
3.2 带远程调用的单元测试
- 使用Mock :在远程调用尚未完成时,可通过Mock进行测试。例如,对
product_fin_client
进行Mock,设置其返回值。 - 编写测试方法 :生成对应的类,并在其中进行修改。使用Mock注解和
product_fin_client
,创建一个cart_vo
对象,并设定其商品ID和数量。对mock对象进行定制,当执行相应方法时,返回一个指定的对象。完成Mock配置后,需对结果进行断言。
四、排查慢方法
在排查方法性能问题时,需要确定方法中哪个位置的执行速度较慢,并测量该方法的耗时。
4.1 测量方法
currentTimeMillis
:使用System.currentTimeMillis()
方法获取开始和结束时间,计算代码执行所用的时间。但该方法依赖系统时间,若系统时间被更改,则结果不准确。nanoTime
:使用System.nanoTime()
方法获取开始和结束时间,计算代码执行所用的时间。该方法返回的时间单位为纳秒,比currentTimeMillis
更加精确。Instant
类 :通过Instant
类可以获取到自1970年1月1日00:00:00 UTC以来的时间戳。利用该方法可获取开始和结束时间,并计算时间差。Stopwatch
:Stopwatch
提供了基础的计时功能,还具备split
、暂停和恢复等强大能力。
4.2 示例代码
currentTimeMillis
示例 :
long start = System.currentTimeMillis();
// 待测试代码
long finish = System.currentTimeMillis();
long timeElapsed = finish - start;
System.out.println("Time elapsed: " + timeElapsed + "ms");
nanoTime
示例 :
long start2 = System.nanoTime();
// 待测试代码
long finish2 = System.nanoTime();
long timeElapsed2 = finish2 - start2;
System.out.println("NanoTime: " + timeElapsed2 / 1000000 + "ms");
Instant
类示例 :
Instant start3 = Instant.now();
// 待测试代码
Instant finish3 = Instant.now();
Duration duration = Duration.between(start3, finish3);
long timeElapsed3 = duration.toMillis();
System.out.println("Time elapsed: " + timeElapsed3 + "ms");
Stopwatch
示例 :
Stopwatch watch = new Stopwatch();
watch.start();
// 待测试代码
watch.split();
System.out.println("Split time: " + watch.getSplitTime() + "ms");
watch.resume();
// 更多待测试代码
System.out.println("Total time: " + watch.getTime() + "ms");
通过以上方法,可以有效地测量代码执行时间,定位性能瓶颈,并针对性地进行优化。