1. 需求
有一个下载pdf的springmvc controller,希望模拟一下并发访问的情况,怎么办呢?
2. 解决方案
由于是pdf,其http响应为
那么我们访问时返回的是二进制,而不是网页那种text/html
于是写一个保存二进制文件的方法
public void saveBinaryFile(URL url) throws IOException { URLConnection uc = url.openConnection(); String contentType = uc.getContentType(); int contentLength = uc.getContentLength(); if (contentType.startsWith("text/") || contentLength == -1 ) { throw new IOException("This is not a binary file."); } InputStream raw = uc.getInputStream(); InputStream in = new BufferedInputStream(raw); byte[] data = new byte[contentLength]; int offset = 0; while (offset < contentLength) { int bytesRead = in.read(data, offset, data.length - offset); if (bytesRead == -1) break; offset += bytesRead; } if (offset != contentLength) { throw new IOException("Only read " + offset + " bytes; Expected " + contentLength + " bytes"); }
String filename = UUID.randomUUID()+".pdf"; try (FileOutputStream fout = new FileOutputStream(filename)) { fout.write(data); fout.flush(); } }
测试方法
Junit本身是不支持普通的多线程测试的,这是因为Junit的底层实现上,是用System.exit退出用例执行的。JVM都终止了,在测试线程启动的其他线程自然也无法执行。
使用Junit多线程测试的开源的第三方的工具包GroboUtils
pom.xml
<!--springmvc中进行多线程测试-->
<dependency>
<groupId>net.sourceforge.groboutils</groupId>
<artifactId>groboutils-core</artifactId>
<version>5</version>
<scope>system</scope>
<systemPath>F:/jar_package/groboutils-core-5.jar</systemPath>
</dependency>
测试方法
@Test
public void testSaveBinaryFile3() throws IOException {
TestRunnable runner = new TestRunnable() {
@Override
public void runTest() throws Throwable {
//测试内容
String urlStr = "http://localhost:8019/xxx”;
URL url = null;
try {
url = new URL(urlStr);
new RenderPdfControllerTest().saveBinaryFile(url);
} catch (IOException e) {
e.printStackTrace();
}
}
};
//Rnner数组,相当于并发多少个
int runnerCount = 5;
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();
}
}
3. 原理
GroboUtils实现原理是让测试主线程等待所有测试子线程执行完成后再退出。想到的办法是Thread中的join方法。看一下其关键的源码实现