背景
最近想用junit写一个多线程实现的单元测试,但是测试结果与期望的不一样,通过debug发现一些实例对象是空的. 这就很让人摸不着头脑了. 😱
原因
通过艰苦卓绝的调查发现竟然是因为junit不支持多线程测试, 这是因为Junit的底层实现上是用System.exit退出用例执行的. JVM都终止了,在测试线程启动的其他线程自然也无法执行
JunitCore代码如下:
/**
* Run the tests contained in the classes named in the <code>args</code>.
* If all tests run successfully, exit with a status of 0. Otherwise exit with a status of 1.
* Write feedback while tests are running and write
* stack traces for all failed tests after the tests all complete.
* @param args names of classes in which to find tests to run
*/
public static void main(String... args) {
runMainAndExit(new RealSystem(), args);
}
/**
* Do not use. Testing purposes only.
* @param system
*/
public static void runMainAndExit(JUnitSystem system, String... args) {
Result result= new JUnitCore().runMain(system, args);
system.exit(result.wasSuccessful() ? 0 : 1);
}
RealSystem.java:
public void exit(int code) {
System.exit(code);
}
解决方法
要想编写多线程Junit测试用例,就必须让主线程等待所有子线程执行完成后再退出, 想到的办法自然是Thread中的join方法.
这个功能GroboUtils
已经替我们实现好了. 所以只需要引入GroboUtils
就能编写多线程测试用例了
GroboUtils官网如下:
http://groboutils.sourceforge.net/
https://mvnrepository.com/artifact/net.sourceforge.groboutils/groboutils-core
下载页面:
http://groboutils.sourceforge.net/downloads.html
Maven依赖:
<dependency>
<groupId>net.sourceforge.groboutils</groupId>
<artifactId>groboutils-core</artifactId>
<version>5</version>
</dependency>
<!-- junit包依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
添加到本地库
下载GroboUtils-core-5.jar
后可以在命令框中执行下面的命令会将jar包添加到本地库
命令如下:
mvn install:install-file -Dfile=groboutils-core-5.jar -DgroupId=net.sourceforge.groboutils -DartifactId=groboutils-core -Dversion=5 -Dpackaging=jar
测试用例
@Test
public void MultiRequestsTest() {
// 构造一个Runner
TestRunnable runner = new TestRunnable() {
@Override
public void runTest() throws Throwable {
//你的测试内容
}
};
int runnerCount = 30;
//Rnner数组,想当于并发多少个。
TestRunnable[] trs = new TestRunnable[runnerCount];
for (int i = 0; i < runnerCount; i++) {
trs[i] = runner;
}
// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
try {
// 开发并发执行数组里定义的内容
mttr.runTestRunnables();
} catch (Throwable e) {
e.printStackTrace();
}
}
参考
1. Junit spring 多线程测试
2. junit 进行spring多线程测试
3. Junit借助Groboutils Core进行并发测试