测试Spring onApplicationEvent的简单方法

yal*_*man 2 java junit spring unit-testing event-listener

我有一个包含功能的应用程序事件监听器:

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//do some stuff
}
Run Code Online (Sandbox Code Playgroud)

如何编写一个单元测试来模拟ContextRefreshedEvent(例如执行我的jar),并测试onApplicationEvent函数是否已完成应做的工作?

Kla*_*aek 5

这是我能想到的最小的独立示例。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.concurrent.LinkedBlockingQueue;

import static org.junit.Assert.assertEquals;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RefreshTest.MyConfig.class})
public class RefreshTest {

    @Autowired
    private MyListener listener;

    @Test
    public void test() {
        assertEquals("Refresh should be called once",1, listener.events.size());
    }

    public static class MyConfig {
        @Bean
        public MyListener listener() {
            return new MyListener();
        }
    }

    public static class MyListener implements ApplicationListener <ContextRefreshedEvent> {
        // you don't really need a threadsafe collection in a test, as the test main thread is also loading the spring contest and calling the handler, 
        // but if you are inside an application, you should be aware of which thread is calling in case you want to read the result from another thread. 
        LinkedBlockingQueue<ContextRefreshedEvent> events = new LinkedBlockingQueue<ContextRefreshedEvent>();
        public void onApplicationEvent(ContextRefreshedEvent  event) {
            events.add(event);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

测试处理程序中的代码与调用处理程序之间是有区别的。不要将代码直接放在处理程序中,而是将代码放在从处理程序调用的另一个bean中,因此您可以在没有处理程序的情况下测试逻辑(通过使用ContextRefreshedEvent您创建的调用它)。刷新上下文时(通常是在加载时)发送刷新事件,因此无需测试。如果您的生产代码中没有调用它,通常会立即注意到。此外,测试和生产环境中上下文的加载可能有所不同,因此,即使编写的测试表明已调用处理程序,也不能保证在生产环境中将调用该处理程序,除非您使用完全相同的方式运行@Configuration-我几乎从来没有做过,因为我经常@Profile在不希望我的测试使用AWS Queues和其他外部IO通道的情况下使用某些配置/ bean的不同实现。