1.部署篇
1.1安装流程
- 在官网下载SonarQube7.4sonarqube官网
ps:本来使用的是推荐的最新9.1版本,在启动bin目录下StartSonar.bat出现无法创建jvm的错误,个人判断为java版本与SonarQube版本不符(jdk版本为1.8.144) - 新建数据库
create database sonar7 default character set utf8 collate utf8_general_ci;
数据库如果要使用Mysql,要使用5.6/5.7版本,soanr.properties有Mysql和其他数据库兼容版本相关描述
- 修改配置文件
下载后配置sonar.properties,加入如下配置(mysql配置自己修改)
sonar.jdbc.url=jdbc:mysql:Mysql IP//Mysql port:/sonar7?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false
sonar.jdbc.username=root #数据库用户名
sonar.jdbc.password=root #数据库密码
sonar.sorceEncoding=UTF-8
sonar.login=admin #web页面注册的账号
sonar.password=admin #web页面注册的密码
- 点击bin目录下StartSonar.bat即可运行,初次启动较慢,因为要初始化数据库,由于本人使用的阿里云服务器,且已经安装了8.0版本Mysql,所以使用Docker部署5.7版本的数据库,映射到8090端口,由于网络传输和容器的影响,构建较慢,大概20-30分钟,耐心等待
- 等待snoar up后,打开http://localhost:9000(也可以提前打开,不过必须等待sonar up后才可以显示相关数据)
1.2 关闭流程
首先关闭StartSonar.bat启动后出现的命令行界面
其次打开任务管理器关闭三个Java进程
ps:之前在启动StartSonar.bat时,一直报该异常
2021.10.17 02:52:33 WARN app[][o.e.t.n.Netty4Transport] exception caught on transport layer [[id: 0xe49808db, L:/127.0.0.1:1623 - R:/127.0.0.1:9001]], closing connection
java.io.IOException: 远程主机强迫关闭了一个现有的连接。
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:192)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
at io.netty.buffer.UnpooledUnsafeDirectByteBuf.setBytes(UnpooledUnsafeDirectByteBuf.java:433)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1100)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:372)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:123)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at java.lang.Thread.run(Thread.java:748)
. 查询logs下日志发现端口被占用,也懒得查了,直接重启电脑,启动成功
1.3汉化插件安装
在sonar的market搜索chinese,点击install,报错,不兼容,去github下载对应版本的插件 ,放到
sonarqube-7.4\extensions\plugins目录下
https://github.com/xuhuisheng/sonar-l10n-zh
该页面提供了sonarqube和汉化插件的对应版本,根据自己的sonarqube版本去下载对应版本的汉化插件即可
2.PowerMock使用篇
前置概念以及注意事项
-
Mock和new出来的对象,对Mock对象set属性是无法成功set的,而new出来的对象可以set属性
-
doReturn().when()和when().return()区别,前者不会执行代码,后者会执行代码,如代码有异常,后者会出现问题,而前者不会(推荐使用前者),两种模式都用于模拟对象方法,在mock实例下使用时,基本上是没有差别的。但是,在spy实例下使用时,when().thenReturn()模式会执行原方法,而doReturn().when()模式不会执行原方法。
-
如果被测方法的参数有boolean类型,那么在stubbing时该参数要使用anyBoolean(),不能使用any(),会报空指针异常
-
@Autowired注入的属性,使用@Mock配置时,mock出的变量名必须相同(如subService),必须和被测试代码中@Autowried注入的SubService同名(subService),否则会报非法参数异常(IllegalArgumentException)
java.lang.IllegalArgumentException: Could not find field ‘productRepository’ of type [null] on target object
@RunWith(PowerMockRunner.class)
@PrepareForTest({xxxServiceImpl.class})
public class xxxServiceImplTest {
@InjectMocks
private xxxServiceImpl xxxService;
@Mock
private SubService subService;
@Before
public void setUp() {
xxxService = PowerMockito.spy(new xxxServiceImpl());
ReflectionTestUtils.setField(xxxService, "subService", subService);
}
@Test
public void methodTest(){
}
tips:
//静态导包,使用assertEquals()简化Assert.assertEquals(),使用any()简化Mockito.any()
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
2.1Controller层测试案例
@RunWith(PowerMockRunner.class)
@PrepareForTest({xxxController.class})
public class xxxControllerTest {
@InjectMocks
private xxxController xxxController;
@Mock
private xxxServiceImpl xxxService;
@Mock
private yyyService yyyService;
@Before
public void setUp() {
// mock私有方法
xxxController = PowerMockito.spy(new xxxController());
ReflectionTestUtils.setField(xxxController, "xxxService", xxxService);
ReflectionTestUtils.setField(xxxController, "yyyService", yyyService);
}
@Test
public void method1() {
//模拟被测方法的返回值
ResponseResult result = xxxController.method1(arg1,arg2);
。。。
//以下按情况选择
assertNull(result.getData());
assertNotNull(result.getData());
assertEquals("targetValue",result.getData());
}
}
2.2service层测试案例
@RunWith(PowerMockRunner.class)
@PrepareForTest(xxxServiceImpl.class})
public class xxxServiceImplTest {
@InjectMocks
private xxxServiceImpl xxxService;
@Mock
private yyyyService yyyService;
@Mock
private zzzRepository zzzRepository;
@Before
public void setUp() {
xxxService = PowerMockito.spy(new xxxServiceImpl());
ReflectionTestUtils.setField(xxxService, "yyyService", yyyService);
ReflectionTestUtils.setField(xxxOrderService, "zzzRepository", zzzRepository);
}
@Test
public void method1() {
//根据被测方法是否有返回值选择
//1.无返回值
PowerMockito.doNothing().when(xxxService).method1(Mockito.any(param1.class), Mockito.any(param2.class));
//构造参数执行被测方法
...
Mockito.verify(xxxService, Mockito.times(1)).method(param1, param2);
//2.有返回值
PowerMockito.doReturn(expected result).when(xxxService).method2(Mockito.any(param1.class), Mockito.any(param2.class));
//构造参数执行被测方法
...
assertNull();
assertNotNull();
assertEquals();
}
}
2.3Dao层(Repository层)测试案例
2.4异常测试案例
2.4.1@Test(expectd = Exception.class)注解形式
@Test(expected= MyException.class)
public String myMethod{
}
2.4.2Assert.assertThrows()
Assert.assertThrows(BusinessException.class, () -> {
xxxService.method(par1,par2);
});
2.5void返回值测试案例
使用verify()方法测试代码调用方法是否执行,是否是预期的执行次数
Mockito.verify(xxxService, Mockito.times(1)).method(any(), any(), any());
2.6使用MybatisPlus的Lambda表达式测试案例
被测代码
List<Product> list = productRepository.lambdaQuery()
.eq(Product::getProdutType, productType)
.eq(Product::getDelFlag, delFlag)
.list();
测试代码
LambdaQueryChainWrapper lambdaQueryChainWrapper = PowerMockito.mock(LambdaQueryChainWrapper.class);
PowerMockito.doReturn(lambdaQueryChainWrapper).when(xxxRepository).lambdaQuery();
PowerMockito.doReturn(lambdaQueryChainWrapper).when(lambdaQueryChainWrapper).eq(any(), any());
PowerMockito.doReturn(list).when(lambdaQueryChainWrapper).list();
2.7PowerMock模拟private方法(method()和invoke()方法)
Method method = PowerMockito.method(xxxRepositoryImpl.class, "method1",Param.class);
Result result=(Result) method.invoke(xxxRepository,param);
3.参考链接
参考:
https://mp.weixin.qq.com/s/LSkTvpsTnBmdOB5nihkxng
https://www.jianshu.com/p/4d9d2534c0d3
待续。。。