如何解决使用vmlens ConcurrentTestRunner时Spring单元测试空指针问题
哈哈,这个问题我之前踩过坑!用vmlens的ConcurrentTestRunner时,Spring的@Autowired确实会失效——因为这个Runner没集成Spring的上下文初始化逻辑,导致Bean根本没被注入。给你几个实用的解决办法:
解决ConcurrentTestRunner下Spring Bean注入空指针的问题
方法一:Spring测试框架+Vmlens注解(最推荐)
不用纠结ConcurrentTestRunner,直接用Spring官方的测试Runner配合Vmlens的并发注解就行,既能享受Spring的依赖注入,又能正常做多线程测试:
import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.vmlens.api.junit.Concurrent; import com.vmlens.api.junit.ThreadCount; @RunWith(SpringJUnit4ClassRunner.class) // 加载你的applicationContext配置文件 @ContextConfiguration(locations = "classpath:applicationContext.xml") public class YourEventProcessorTest extends AbstractJUnit4SpringContextTests { @Autowired private EventStore eventStore; // 现在能正常注入了 @Autowired private EntityAppender entityAppender; @Test @Concurrent // 开启Vmlens的并发测试 @ThreadCount(8) // 指定并发线程数,按需调整 public void testConcurrentEventHandling() { // 直接用注入好的Bean写测试逻辑 eventStore.save(...); entityAppender.append(...); } }
这里继承AbstractJUnit4SpringContextTests是可选的,但继承后可以直接使用Spring上下文相关的工具方法,会更方便。
方法二:手动加载Spring上下文(适合不想改Runner的场景)
如果你一定要用ConcurrentTestRunner,可以手动初始化Spring上下文,然后从上下文里获取Bean:
import org.junit.Before; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.vmlens.junit.ConcurrentTestRunner; @RunWith(ConcurrentTestRunner.class) public class YourConcurrentTest { private static ApplicationContext springContext; private EventStore eventStore; private EntityAppender entityAppender; @BeforeClass public static void initSpringContext() { // 加载你的applicationContext.xml springContext = new ClassPathXmlApplicationContext("applicationContext.xml"); } @Before public void initBeans() { // 从上下文获取Bean eventStore = springContext.getBean(EventStore.class); entityAppender = springContext.getBean(EntityAppender.class); } @Test public void testConcurrentProcessing() { // 测试逻辑,直接用获取到的Bean } }
这种方式完全绕开了Spring的测试Runner,自己控制上下文生命周期,缺点是需要手动管理Bean的获取,不如第一种优雅,但胜在灵活。
方法三:自定义Runner(进阶,不推荐)
如果有特殊需求必须同时兼容两个Runner的逻辑,可以自定义一个JUnit Runner,同时集成ConcurrentTestRunner和SpringJUnit4ClassRunner的功能。不过这种方式需要深入了解JUnit的Runner机制,代码复杂度高,一般不建议用,除非前两种方法都满足不了你的需求。
内容的提问来源于stack exchange,提问作者S.min Chen
相关产品推荐
相关产品推荐

