我有一个 Spring应用程序监听器实现ApplicationListener<ContextRefreshedEvent>
,如下所示:
@Profile({ Profiles.DEFAULT, Profiles.CLOUD, Profiles.TEST, Profiles.DEV })
@Component
public class BootstrapLoaderListener implements ApplicationListener<ContextRefreshedEvent>, ResourceLoaderAware, Ordered {
private static final Logger log = Logger.getLogger(BootstrapLoaderListener.class);
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
@Autowired
private DayToTimeSlotRepository dayToTimeSlotRepository;
@Autowired
private LanguageRepository languageRepository;
private ResourceLoader resourceLoader;
@Override
@Transactional
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
initApplication();
}
private void initApplication() {
if (dayToTimeSlotRepository.count() == 0) {
initDayToTimeSlots();
}
if (languageRepository.count() == 0) {
initLanguages();
}
}
private void initDayToTimeSlots() {
for (Day day : Day.values()) {
for (TimeSlot timeSlot : TimeSlot.values()) {
DayToTimeSlot dayToTimeSlot = new DayToTimeSlot();
dayToTimeSlot.setDay(day);
dayToTimeSlot.setTimeSlot(timeSlot);
dayToTimeSlot.setDisabled(isDayToTimeSlotDisabled(timeSlot, day));
dayToTimeSlotRepository.save(dayToTimeSlot);
}
}
}
...
我依赖这个监听器类来插入未更新或删除的引用数据,并且我有许多使用此类的Spring集成测试,其中一个失败,因为没有通知监听器(initDayToTimeSlots
是没有被援引)。
我试图通过调试测试来确定问题的来源,我注意到当我自己运行有问题的测试类时,类中包含的测试传递(表示通知了侦听器)但是当我将所有应用程序测试类一起运行,不会通知侦听器导致测试失败(表明某些其他测试更改/污染了上下文)。
以下是有问题的测试类:
@ActiveProfiles({ Profiles.TEST })
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
public class RegularDayToTimeSlotsTest {
private static int NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK = 25;
@Before
public void setup() {
//org.hsqldb.util.DatabaseManagerSwing.main(new String[] { "--url", "jdbc:hsqldb:mem:bignibou", "--noexit" });
}
@Autowired
private AdvertisementService advertisementService;
@Test
public void shouldNotContainSaturdayNorSunday() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).onProperty("day").excludes(Day.SATURDAY, Day.SUNDAY);
assertThat(regularDayToTimeSlots).onProperty("day").contains(Day.MONDAY, Day.THUESDAY);
}
@Test
public void shouldNotContainEveningNorNighttime() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).onProperty("timeSlot").excludes(TimeSlot.EVENING, TimeSlot.NIGHTTIME);
assertThat(regularDayToTimeSlots).onProperty("timeSlot").contains(TimeSlot.MORNING, TimeSlot.LUNCHTIME);
}
@Test
public void shouldContainCorrectNumberOfDayToTimeSlots() {
Set<DayToTimeSlot> regularDayToTimeSlots = advertisementService.retrieveRegularDayToTimeSlots();
assertThat(regularDayToTimeSlots).hasSize(NUMBER_OF_REGULAR_DAY_TO_TIME_SLOTS_IN_WEEK);
}
}
我很困惑地看到prepareRefresh()
方法中的finishRefresh()
和AbstractApplicationContext.refresh
方法确实已被调用但我的听众未被通知...
有没有人有任何线索?
P.S。我知道我可以使用@DirtiesContext
来获得新的上下文,我也知道最好不要依赖应用程序监听器进行测试,但我非常渴望了解这里出了什么问题。因此这篇文章。
编辑1 :当我单独调试有问题的测试类时,我注意到事件源的类型为GenericApplicationContext
,并且如上所述,测试通过了OK,因为收到了监听器。但是,当所有测试类一起运行时,奇怪的是,事件源的类型为GenericWebApplicationContext
,SimpleApplicationEventMulticaster
中没有找到侦听器:
@Override
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener<?> listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
编辑2 :我在编辑1 中的评论让我问自己有什么责任来确定上下文配置的唯一性......
例如,我只有两个具有以下上下文配置的测试类:
@ContextConfiguration(classes = { FullIntegrationTestConfiguration.class, BaseTestConfiguration.class })
我猜他们都会使用相同的缓存上下文,不是吗?现在第三个类可以使用相同的缓存上下文,即使它没有完全相同的上下文配置吗?
为什么我的测试得到GenericWebApplicationContext
以上?
答案 0 :(得分:1)
我在编辑1中的评论让我问自己有什么责任 确定上下文配置的唯一性......
构成上下文缓存键的元素在参考手册的“测试”一章的Context caching部分中有所描述。
例如,我只有两个具有以下上下文的测试类 配置:
@ContextConfiguration(classes = { FullIntegrationTestConfiguration.class,BaseTestConfiguration.class})
我猜他们都会使用相同的缓存上下文,不是吗?
如果他们只按照确切的顺序声明那两个配置类,那么是。
现在,第三个类可以使用相同的缓存上下文,即使它没有 具有完全相同的上下文配置?
没有
为什么我的测试会获得上面的GenericWebApplicationContext?
只有在您的测试类(或其中一个超类)使用GenericWebApplicationContext
进行注释时,才会加载@WebAppConfiguration
。
如果您遇到与此相反的行为,那么您发现了一个错误,如果您可以在issue repository和create a corresponding JIRA issue中针对“{3}}生成缩小的测试项目,我们将非常感谢Spring Framework“及其”测试“组件。
谢谢,
Sam(Spring TestContext Framework的作者)