我创建了一个EventEmitter,它将事件传递给新线程中的侦听器:
public class EventEmitter{
private Map<String,List<EventListener>> listeners = new HashMap<String,List<EventListener>>();
private Executor executor = Executors.newCachedThreadPool();
protected EventEmitter(Executor executor){
this.executor = executor;
}
public void publish(Event e) {
listeners.get(e.getClass().toString()).stream().forEach(listener->{
executor.execute(()->{listener.beNotifiedOfEvent(e);});
});
}
public void subscribe(EventListener listener,Class<?> eventClass) {
assert Arrays.asList(eventClass.getInterfaces()).contains(Event.class);
List<EventListener> listenersThatListenToIt = listeners.get(eventClass.toString());
if(listenersThatListenToIt!=null){
listenersThatListenToIt.add(listener);
} else {
listenersThatListenToIt = new ArrayList<EventListener>();
listenersThatListenToIt.add(listener);
listeners.put(eventClass.toString(),listenersThatListenToIt);
}
}
}
我还会在收到事件两秒后在监听器中打印一条消息:
@Component
public class StudentRegisteredEventListener implements EventListener {
@Override
public void beNotifiedOfEvent(Event e) {
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
StudentRegisteredEvent studentRegisteredEvent = (StudentRegisteredEvent) e;
System.out.println("Received student registered event! Student's name is: "+studentRegisteredEvent.getRegisteredStudent());
}
}
我有以下JUnit测试:
@Test
public void test_emitter_notifies_listener() {
//given
EventEmitter emitter = new CachedThreadPoolEventEmitter();
//StudentRegisteredEvent event = new StudentRegisteredEvent();
EventListener listener = Mockito.mock(StudentRegisteredEventListener.class);
Student registeredStudent = new Student();
registeredStudent.setName("studentName");
//when
emitter.subscribe(listener,StudentRegisteredEvent.class);
emitter.publish(new StudentRegisteredEvent(registeredStudent));
//then
System.out.println("end of test");
}
我的问题是当父线程在&#34; beNotifiedOfEvent&#34;结束之前结束时调用,来自侦听器方法的行不打印,所以我只看到&#34;测试结束&#34;在控制台上。
我感兴趣的是:这种行为的原因是什么,以及这是否会在测试环境之外起作用。我计划从Spring MVC控制器发布事件。在父线程完成执行后,这是否可以保证完成?
答案 0 :(得分:2)
这不是线程终止而是整个过程。 JUnit kills the process when the test finishes,所以甚至非守护程序线程都不能使JUnit测试进程保持活动状态。(如果你仔细想想它就完全是直截了当的,没有人想要在完成实际测试后运行测试进程)。 In Java, threads do not have a hierarchy,没有“父”线程。但是几乎每个应用程序都有某种“主”线程。 JUnit有自己的主线程,在其中运行测试,最后调用System.exit(0);
。
如果要测试某些定时事件,则必须在测试用例中明确地等待线程。另外,我建议使用ScheduledExecutorService
代替Thread.sleep
- s。
答案 1 :(得分:1)
如果它在测试环境中不起作用,你不应该接受任何人的说法,它可能在测试环境之外工作。首先让您的测试正常工作。
如果您希望测试正常完成,那么您必须等待它产生的所有线程结束。假设您的Executor
实际上是ExecutorService
,请按以下步骤操作:
executorService.shutdown();
try
{
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e)
{
...
}
当上面的代码正在执行时,您的任务应该运行完成,因此您应该在任务结束之前看到显示的消息。