在使用Junit编写单元测试的时候,我们可以使用的套件有@Before、@After、@BeforeClass、@AfterClass等。在JMH中,有没有哪些套件方法可以支持对基准测试方法的初始化以及资源回收呢?答案是有的
1 Setup以及TearDown
JMH提供了两个注解@Setup和@TearDown用于套件测试,其中@Setup会在每一个基准测试方法执行前被调用,通常用于资源的初始化,@TearDown则会在基准测试方法被执行之后被调用,通常可用于资源的回收清理工作:
@BenchmarkMode(Mode.AverageTime)
@Fork(1)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
// 开启5个线程测试
@Threads(5)
// 设置为线程间共享资源
@State(Scope.Thread)
@Warmup(iterations = 5)
@Measurement(iterations = 10)
public class JMHExample11 {
/**
* 定义了一个List<String>,但是没有对其进行初始化
*/
private List<String> list;
/**
* 将方法标记为@Setup,执行初始化操作
*/
@Setup
public void setUp(){
this.list = new ArrayList<>();
}
/**
* 定义一个测试基准方法
*/
@Benchmark
public void test(){
// do nothing
}
/**
将方法标记为@TearDown,运行资源回收甚至断言的操作
*/
@TearDown
public void tearDown() {
// 断言list中的元素个数大于0,很明显,test基准测试将会失败
assert this.list.size() > 0 : "The list elements must greater than zero";
}
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(JMHExample11.class.getSimpleName())
// 激活断言,enable assertion的意思
.jvmArgs("-ea")
.build();
new Runner(options).run();
}
}
运行,断言失败
java.lang.AssertionError: The list elements must greater than zero
at study.wyy.juc.jmh.JMHExample11.tearDown(JMHExample11.java:53)
at study.wyy.juc.jmh.generated.JMHExample11_test_jmhTest.test_AverageTime(JMHExample11_test_jmhTest.java:165)
at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:453)
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:437)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
2 Level
使用Setup和TearDown时,在默认情况下,Setup和TearDown会在一个基准方法的所有批次执行前后分别执行,
如果需要在每一个批次或者每一次基准方法调用执行的前后执行对应的套件方法,则需要对@Setup和@TearDown进行简单的配置
- Trial:Setup和TearDown默认的配置,该套件方法会在每一个基准测试方法的所有批次执行的前后被执行。
- Iteration:由于我们可以设置Warmup和Measurement,因此每一个基准测试方法都会被执行若干个批次,如果想要在每一个基准测试批次执行的前后调用套件方法,则可以将Level设置为Iteration。
- Invocation:将Level设置为Invocation意味着在每一个批次的度量过程中,每一次对基准方法的调用前后都会执行套件方法。
如何设置:
@Setup(Level.Invocation)
public void setUp()