尝试测试我的一个类可以处理在多个线程上的访问。我有一个JUnit测试,在其中创建了一个实现Runnable
并运行我的类的类。
当我运行execute时,它在run()方法中到达一行,并且仅在该线程上退出而不报告任何问题,我已经用Try-Catch(Throwable)对其进行了包装,但仍然没有任何迹象错误的。
这是我的代码:
class ConcurrencyTests {
class ConcurrentComponentTracker implements Runnable {
private String component;
ConcurrentComponentTracker(String component) {
this.component = component;
}
@Override
public void run() {
try {
System.out.printf("Component to track: [%s]\n", component);
ParserHandler parserHandler = new ParserHandler();
System.out.println(parserHandler.componentTracker(component));
}
catch (Throwable t) {
t.printStackTrace();
}
}
}
@Test
void runRunner() {
ExecutorService executor = Executors.newFixedThreadPool(4);
String[] componentsToTrack = {"x", "y", "z"};
executor.execute(new ConcurrentComponentTracker(componentsToTrack[0]));
executor.execute(new ConcurrentComponentTracker(componentsToTrack[1]));
executor.execute(new ConcurrentComponentTracker(componentsToTrack[2]));
}
}
输出:
Component to track: [x]
Component to track: [y]
Component to track: [z]
似乎只是在ParserHandler实例化行上退出而不报告任何内容。当尝试调试并进入该行时,它只是跳到最后而没有让我检查ParserHandler类的实例。
答案 0 :(得分:2)
Whomever在评论中回答,然后删除它为我解决了问题。我的主要JUnit线程没有等待其他线程完成。因此,我将这些行添加到最后,并按预期工作:
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e) {
e.printStackTrace();
}
答案 1 :(得分:0)
JUnit测试应该实际测试和验证结果。在这种特殊情况下,您的测试产生的输出应由开发人员/测试人员验证,因此这不是自动化的。
建议您使用Future<?>
来跟踪任务执行状态。对于Runnable
的任务,如果任务成功执行,则get()
的{{1}}方法将返回Future<?>
,否则将转发给您null
包裹的异常。代码将如下所示:
ExecutionException
在执行此操作之前,应删除@Test
void runRunner() {
ExecutorService executor = Executors.newFixedThreadPool(3);
String[] componentsToTrack = {"x", "y", "z"};
assertNull(executor.submit(new ConcurrentComponentTracker(componentsToTrack[0]).get());
assertNull(executor.submit(new ConcurrentComponentTracker(componentsToTrack[1]).get());
assertNull(executor.submit(new ConcurrentComponentTracker(componentsToTrack[2]).get());
// cleanup and shutdown pool
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
// ignore this
}
}
方法内的try/catch
块。
您可能需要改进的另一件事是使executor成为测试类的一个字段,并使用run()
,@BeforeClass
,...通过传统的JUnit生命周期对其进行管理,以进行初始化,测试之间的清理,关闭优雅地游泳池。请记住,从资源的角度来看,线程池并不是那么便宜。
希望有帮助!
PS ,如果您的目标是对@Before
进行并行处理,则可以将ConcurrentComponentTracker
存储在某些集合中,并在提交所有任务后运行断言。