我在多线程中测试事件处理器。所以我在我的测试用例中使用了vmlens的concurrent-junit。 但是当我使用ConcurrentTestRunner而不是SpringJunit4ClassRunner时,我在autowired bean时得到了nullpoint异常。 这是我的pom
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vmlens</groupId>
<artifactId>concurrent-junit</artifactId>
<version>1.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>2.6.0</version>
<scope>test</scope>
</dependency>
测试用例源代码:
import com.anarsoft.vmlens.concurrent.junit.ConcurrentTestRunner;
import com.anarsoft.vmlens.concurrent.junit.ThreadCount;
@RunWith(ConcurrentTestRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class EventListenerTest {
@Autowired
private EventStore es; //defined in applicationContext.xml
@Autowired
private EntityAppender ea; //a @Component
......
@Test
@ThreadCount(10)
public final void testDefaultListener() {
Long bef = es.countStoredEvents();// nullpoint exception
TestEntity1 t1 = ea.appWithDefaultListener();// nullpoint exception
......
}
}
显然,豆子没有正确注射。 有没有什么办法解决这一问题?我应该扩展AbstractJUnit4SpringContextTests吗?
此处附上最新代码:
EventStore是一个Jpa存储库:
public interface EventStore extends JpaRepository<DomainEvent, Long>{};
的applicationContext.xml
<aop:config proxy-target-class="true" />
<context:annotation-config />
<jpa:repositories base-package="com.my"></jpa:repositories>
EntityAppender仅用于测试。
@Component
public class EntityAppender {
@Autowired
private TestEntity1Repository myRepository; //another Jpa repository
public EntityAppender() {
super();
}
@Transactional
public TestEntity1 appWithDefaultListener() {
TestEntity1 t1 = new TestEntity1(UUID.randomUUID().toString().replaceAll("-", ""), "aaaaaaaaaaaa", 44,
LocalDate.now());
return myRepository.save(t1);
}
...
}
测试用例:
import com.anarsoft.vmlens.concurrent.junit.ConcurrentTestRunner;
import com.anarsoft.vmlens.concurrent.junit.ThreadCount;
@RunWith(ConcurrentTestRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class EventListenerTest {
@ClassRule
public static final SpringClassRule springClassRule = new SpringClassRule();
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
@Autowired
private EventStore es;
@Autowired
private EntityAppender ea;
......
@Before
public void setUp() throws Exception {
bef = es.count(); //<====nullpoint exception due to es being null here
}
@Test
@ThreadCount(10)
public final void testDefaultListener() {
bef = es.count(); //<====== es worked well here
TestEntity1 t1 = ea.appWithDefaultListener();
......
}
}
答案 0 :(得分:3)
从Spring 4.2开始,当你因某些其他原因需要提供自己的JUnit Runner
时(例如ConcurrentTestRunner
或Mockito的MockitoJUnitRunner
),Spring提供了一个单独的机制初始化单元测试的ApplicationContext
和元配置。
此机制是两个JUnit 4规则的组合。这在官方文档here中有记录。
org.springframework.test.context.junit4.rules
包提供了 遵循JUnit 4规则(在JUnit 4.12或更高版本上受支持)。
SpringClassRule
SpringMethodRule
SpringClassRule
是一个支持类级功能的JUnitTestRule
Spring TestContext框架;而SpringMethodRule
是一个 JUnitMethodRule
,支持实例级和方法级 Spring TestContext Framework的特性。
您的单元测试类应该至少包含
@ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
这是一个使用MockitoJUnitRunner
同时仍然使用Spring的TestContext框架的完整示例:
@ContextConfiguration(classes = ConfigExample.class)
@RunWith(MockitoJUnitRunner.class)
public class Example {
@ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
@Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
@Autowired
private Foo foo;
@Mock
private Runnable runnable;
@Test
public void method2() {
Mockito.doNothing().when(runnable).run();
foo.bar(runnable);
Mockito.verify(runnable).run();
}
}
@Configuration
class ConfigExample {
@Bean
public Foo Foo() {
return new Foo();
}
}
class Foo {
public void bar(Runnable invoke) {
invoke.run();
}
}