IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 2021-07-05 -> 正文阅读

[开发测试]2021-07-05

1.单元测试相关知识
单元测试概念

相关注解
@Test 标识当前是一个单元测试方法
@Before会在单元测试执行之前做一些事情
@Ignore:这个注释是用来忽略有关不需要执行的测试的。

断言Assert

简单来讲 断言就是"判断"。 在单元测试中 我们可以针对接口预期的返回结果,进行判断

Junit所有的断言都包含在 Assert 类中。

Assert 类中的一些有用的方法列式如下:


void assertEquals(boolean expected, boolean actual):检查两个变量或者等式是否平衡
void assertTrue(boolean expected, boolean actual):检查条件为真
void assertFalse(boolean condition):检查条件为假
void assertNotNull(Object object):检查对象不为空
void assertNull(Object object):检查对象为空
void assertSame(boolean condition):assertSame() 方法检查两个相关对象是否指向同一个对象
void assertNotSame(boolean condition):assertNotSame() 方法检查两个相关对象是否不指向同一个对象
void assertArrayEquals(expectedArray, resultArray):assertArrayEquals() 方法检查两个数组是否相等

使用单元测试好处

可以书写一系列的测试方法,对项目所有的接口或者方法进行单元测试。
启动后,自动化测试,并判断执行结果, 不需要人为的干预。(使用Assert断言)
只需要查看最后结果,就知道整个项目的方法接口是否通畅。(以防止修改代码之后出现不必要的bug遗漏)
添加,删除,屏蔽测试方法,不影响其他的测试方法。(比如可以对方法、类上添加@Ignore注解以跳过这个测试 但是不推荐)

2.单元测试实操

单元测试中含有Rpc的测试思路
单元测试中含有RPC带来的问题:
由于强依赖于对方的服务,如果远程服务未发布,或者对方服务出现问题,将会导致单元测试的失败。
RPC可能涉及到一系列的逻辑,比如控制中枢接口,即使我们传递了正确的参数,依然需要在雅典娜上进行一系列的配置 才会返回命中,其实他具体的规则 我们是不关心的
如果直接调用RPC ,我们就需要去真实去修改各种配置项目,已达到命中的目的,比较费时。
针对以上的几点,我们可以使用Bean后置处理器,以及Mockito工具,进行模拟接口请求,使得原有需要借助网络的请求,直接在本地模拟出来返回值
Mock本地模拟的好处
灵活,不需要关注对方RPC服务一系列的规则配置,可以自定义返回值【重要】,入参
稳定,不需要依赖网络,和真实的服务。确保单元测试可以稳定运行

使用Mockito 进行Mock

mockito配可以将被注解注入的对象生成一个Mock对象。我们可以针对这个Mock对象,进行预期的行为

    例如我们要测试A类,A类的依赖关系如下

假如Class B是一个IO/RPC引用,我们可以尝试去创建mock对象

       例子:
@Mock
IntermodalServiceI intermodalServiceI; //这是一个RPC服务  相当于ClassB
@Test
public void testMock(){
//打桩 //自定义行为
IntermodalApp intermodalApp = new IntermodalApp();
intermodalApp.setAppName("Mock游戏名字");
Mockito.when(intermodalServiceI.selectAppByGameId(1)).thenReturn(ResponseEntity.success(intermodalApp));

//调用rpc测试
IntermodalApp intermodalAppReturn = ResponseEntity.wrap(intermodalServiceI.selectAppByGameId(2));
System.out.println(intermodalAppReturn.getAppName()); //这个还会走真实的RPC

intermodalAppReturn = ResponseEntity.wrap(intermodalServiceI.selectAppByGameId(1));
System.out.println(intermodalAppReturn.getAppName()); //这个会输出Mock的游戏名字
}
       如果传递任何的Int参数,我们都希望能够进行Mock调用,可以这样写
Mockito.when(intermodalServiceI.selectAppByGameId(Mockito.anyInt())).thenReturn(ResponseEntity.success(intermodalApp));

效果

以上简单的写法,可以模拟真实的dubbo请求,并自定义响应。但是真实的情况往往没那么简单

我们依然要测试Class A, ClassA 引用了本地的ClassB(B不需要Mock) , Class D是我们需要Mock的对象。如图:

举例 ,创建一个ClassB

@Service
public class ClassB {

@DubboReference
IntermodalServiceI intermodalServiceI; //Class D

public IntermodalApp testB(int gameId){
return ResponseEntity.wrap(intermodalServiceI.selectAppByGameId(gameId));
}
}

这时候Mock RPC是会失败的,这是因为单元测试中虽然对RPC进行了Mock和打桩。但是和ClassB中会真实创建RPC对象的引用,这两个RPC并不是同一个对象。所以导致了失败

尝试在真实业务中加上@Getter方法,手动使用Mockito.mock()创建Mock对象

@Service
public class ClassB {

  @Getter
  @DubboReference
  IntermodalServiceI intermodalServiceI; //Class D

  public IntermodalApp testB(int gameId){
    return ResponseEntity.wrap(intermodalServiceI.selectAppByGameId(gameId));
  }
}

//发现还是不行,这是因为我们只是基于某一个类 生成了Mock对象,然而实际ClassB中注入的依然是原始Rpc代理。对象不是同一个 自然无法Mock成功

@Test
public void testMock(){
	//打桩 //自定义行为
	IntermodalApp intermodalApp = new IntermodalApp();
	intermodalApp.setAppName("Mock游戏名字");
	IntermodalServiceI mockServiceI = Mockito.mock(classB.getIntermodalServiceI().getClass());
	Mockito.when(mockServiceI.selectAppByGameId(Mockito.anyInt())).thenReturn(ResponseEntity.success(intermodalApp));

	//调用Class B测试
	IntermodalApp intermodalAppReturn = classB.testB(2);
	System.out.println(intermodalAppReturn.getAppName());

}

解决方式:

写一个Bean后置处理器, 偷偷的把真实代理 替换成我们Mock对象。这样就可以满足真实业务场景了

Mock RPC接口 / Mock Mq的生产者

注册这个bean处理器,并在BaseTest中

       @Import({TestConfig.class})

使用方式:

@Autowired
ClassB classB;

@Test
public void testMock(){
  //打桩 //自定义行为
  IntermodalApp intermodalApp = new IntermodalApp();
  intermodalApp.setAppName("Mock游戏名字");
  Mockito.when(classB.getIntermodalServiceI().selectAppByGameId(Mockito.anyInt()))
                       .thenReturn(ResponseEntity.success(intermodalApp));

  //调用Class B测试
  IntermodalApp intermodalAppReturn = classB.testB(2);
  System.out.println(intermodalAppReturn.getAppName());
  Assert.assertNotNull("游戏数据不能为空!" , intermodalApp );
}

3.单元测试覆盖率

编写业务Biz层, 每写完一个业务方法,即开始对其进行测试。一般来说每个单元测试方法下都应该有一个Assert断言判断

举例 限额功能 流程:针对一个用户 ,首先调用控制中枢接口判断游戏是否开启限额开关,如果开启调用实名认证接口 拿到用户的年龄。再根据年龄进行一系列的计算统计,返回对应的额度限制【简化的流程】

首先构思应该减少依赖,因为限额计算依赖于 控制中枢返回值,首先将控制中枢的调用拆出去。 这样对于限额计算的单元测试就更加方便.。否则控制中枢就必须返回true 才可以测的到限额。

针对限额方法进行单元测试(注意使用的是Junit下的@Test注解 别用错了)

测试

@Test(expected = BusinessServiceException.class)  //expected代表这个单元测试预期抛出什么异常类

public void validRechargeLimit() {
  RealNameAuthResponse realNameAuthResponse= RealNameAuthResponse.builder().uuid(UUID).age(8).cardNo("dsfadfsdf").packageName("com.meta.box")
    .verifyStatus(1).build();
  //参数1 下单扩展信息 参数2:本次实付金额 参数3:实名信息 包含用户的年龄等等
  validOrderBiz.validRechargeLimit(null , 5000 , realNameAuthResponse);
}

略,观察sonar,本地的coverage, 看代码覆盖情况,针对业务情况进行增加Case!!!!!!!!!!!!!

4.集成jacoco插件生成测试报告 提交至sonar(略)

主pom添加sonar配置属性

<!-- Sonar-Jacoco -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.coverage.jacoco.xmlReportPaths>
${project.basedir}/../meta-finance-base-start/target/site/jacoco-aggregate/jacoco.xml
</sonar.coverage.jacoco.xmlReportPaths>
<sonar.language>java</sonar.language>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
</plugin>

start模块中添加插件,主要是配置聚合报告(说白了就是start项目依赖那个模块,就会检测哪块的覆盖,一般是依赖service模块)

<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-07-07 00:07:16  更:2021-07-07 00:07:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 18:40:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码