提升mavne test时间
背景
公司最近对代码的行覆盖提了要求,虽然说更多的UT可以在一定程度上提升代码质量,但是由于代码的量很大导致maven build出包的速度受到了很大的影响,一度增加到了40min。(我们公司一定要先build 通过才能将代码合并到Master)在这样的情况下领导要求大幅缩短UT耗费的时间
增加内存
通过增加分析build过程中的GC log,发现经过多次的Full GC,每次都会消耗掉不少时间,通过修改pom.xml来修改
<argLine>-noverify -Xms10G -Xmx10G -XX:NewSize=3G -XX:-UseAdaptiveSizePolicy -XX:ReservedCodeCacheSize=480M -XX:MetaspaceSize=1280M</argLine>
具体的大小需要多试验几次,大部分参数大家应该都很熟悉比较特殊的是-XX:-UseAdaptiveSizePolicy
和XX:ReservedCodeCacheSize
,分别简单介绍一下
-XX:-UseAdaptiveSizePolicy,关闭AdaptiveSizePolicy,JDK 1.8 默认使用 UseParallelGC 垃圾回收器,该垃圾回收器默认启动了 该功能,会根据GC的情况自动计算计算 Eden、From 和 To 区的大小;
我们在观察GC日志时发现了以下日志
SUREFIRE-859: [Full GC (Ergonomics) [PSYoungGen: 3064832K->0K(3216896K)] [ParOldGen: 6530489K->6514820K(6990848K)] 9595321K->6514820K(10207744K), [Metaspace: 1093533K->1093316K(2080768K)], 29.8133768 secs] [Times: user=102.30 sys=40.04, real=29.82 secs]
Full GC (Ergonomics)
表明动态调整了几个分区的大小,因为是maven build我们修改为了固定值。
XX:ReservedCodeCacheSize,该参数是JvM虚拟机调优中调整内存大小的一个设置参数,值得大小设置直接影响到Code Cache的大小,而jvm编译的代码有常常存放在Code Cache中,而Code Cache的空间内存又支撑着jvm的正常运行,如果该空间不足jvm虚拟机将会发生问题,并且性能持续降低。JVM默认的CodeCache是240M。
CodeCache: size=245760Kb used=243229Kb max_used=243298Kb free=2530Kb
SUREFIRE-859: bounds [0x000000010f431000, 0x000000011e431000, 0x000000011e431000]
total_blobs=64731 nmethods=63978 adapters=663
compilation: disabled (not enough contiguous free space left)
Java HotSpot(TM) 64-Bit Server VM warning: CodeCache is full. Compiler has been disabled.
Java HotSpot(TM) 64-Bit Server VM warning: Try increasing the code cache size using -XX:ReservedCodeCacheSize=
通过以上几个参数的配置,我们buil的时间从40分钟缩短到了20分钟,成果显著。但是我们可以进一步压缩时间。
并发执行单元测试
前面提到我们build大部分时间都耗在了Test上,如果能够并发的执行UT,也可以在一定程度上缩短时间。
我们使用的测试框架是TestNG,TestNG本身支持并发操作,我们可以通过配置文件suit.xml
来配置,suit的详细介绍可以参考https://www.devtalking.com/articles/testng-powermock/,下面提供一个例子,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="site-service-test-suite-parallel">
<test name="site-service-test-queue">
<method-selectors>
<method-selector>
<selector-class name="QueueMethodSelector" priority="-1" />
</method-selector>
</method-selectors>
<packages>
<package name="your.package.*"/>
</packages>
</test>
<test name="site-service-test-parallel" parallel="classes" thread-count="8" >
<method-selectors>
<method-selector>
<selector-class name="ParallelMethodSelector" priority="-1"/>
</method-selector>
</method-selectors>
<packages>
<package name="your.package.*"/>
</packages>
</test>
</suite>
可有看到我们的文件里区分了两个test,一个使用了parallel标签和thread-count标签,这两个标签指明使用的并发级别和线程数;另外一个没有使用表明串行执行。除此之外这两个最主要的区别在于method-selector
标签里的值不同,因为我们的UT重度依赖PowerMock,导致一些UT无法并发执行(PrepareForTest注解会修改字节码),所以我们自定义了一个类扫描器,对UT进行分类。
public class ParallelMethodSelector implements IMethodSelector {
private static final Logger logger = LoggerFactory.getLogger(ParallelMethodSelector.class);
@Override
public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod method, boolean isTestMethod) {
if (!isTestMethod)
return true;
Class<?> clazz = method.getRealClass();
if (clazz.isAnnotationPresent(PrepareForTest.class))
return false;
Class<?> superClass = clazz.getSuperclass();
if (Objects.nonNull(superClass) && superClass.isAnnotationPresent(PrepareForTest.class))
return false;
return true;
}
@Override
public void setTestMethods(List<ITestNGMethod> testMethods) {
}
}
TestNG 6.9
在并发上有Bug,最好使用更好的版本
在此之外,maven也提供了-T
参数,可以在并发的build不同的module。
放弃PowerMock
最近在做jdk17的升级,