Как получить Spring для автоматического тестирования класса интеграции с использованием нескольких контекстов?
В одном из моих тестов интеграции используются несколько файлов контекста Spring. Кажется, что Spring только autwires в beans из первого контекста, а не второго. Кто-нибудь знает, что я делаю неправильно или как решить проблему?
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/META-INF/spring/applicationContext.xml",
"classpath:/META-INF/spring/applicationContext-security.xml"})
@Configurable
public class UserDetailsServiceImplIntegrationTest {
@Autowired
UserDataOnDemand dod;
// @Autowired does not work for this bean from applicationContext-security.xml
UserDetailsService userDetailsService;
@Before
public void setup() {
dod.init();
// workaround for autowiring problem
userDetailsService = (UserDetailsService)ctx.getBean("userDetailsService");
}
@Test
public void testLoadUser() {
UserDetails ud = userDetailsService.loadUserByUsername("[email protected]");
Assert.assertEquals("[email protected]", ud.getUsername());
}
}
Я использую Spring 3.0.3.
Вот трассировка стека, когда я раскомментирую @Autowired строку для UserDetailsService:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'za.co.acme.app.security.UserDetailsServiceImplIntegrationTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.security.core.userdetails.UserDetailsService za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.userDetailsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1064)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
at org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:140)
at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:59)
at org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(AbstractDependencyInjectionAspect.aj:89)
at za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.(UserDetailsServiceImplIntegrationTest.java:25)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:202)
bean определенно существует, так как работает поиск по имени, и он имеет правильный тип.
Ответы
Ответ 1
Обходной путь заключается в создании нового файла конфигурации (пусть его называют "test-configuration.xml" ), который включает в себя как applicationContext.xml, так и applicationContext-security.xml. Затем вы можете использовать эти конфигурации в своих тестах.
тест-configuration.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath:/META-INF/spring/applicationContext.xml"/>
<import resource="classpath:/META-INF/spring/applicationContext-security.xml"/>
</beans>
UserDetailsServiceImplIntegrationTest.java:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-configuration.xml")
@Configurable
public class UserDetailsServiceImplIntegrationTest {
...
}
Ответ 2
У меня была та же проблема, решение исправлено, моя проблема заключается в переключении bean через интерфейс. (т.е. ваш ссылочный тип bean должен быть Interface вместо класса реализации
В вашем случае измените конкретную ссылку класса UserDetailsService
с ее интерфейсом.
Пример:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/META-INF/spring/applicationContext.xml",
"classpath:/META-INF/spring/applicationContext-security.xml"})
@Configurable
public class UserDetailsServiceImplIntegrationTest {
//modified code
@Autowired
IUserDetailsService userDetailsService;
//your test cases follows
}
ПРИМЕЧАНИЕ: Я знаю, что это не будет разумным решением. Но просто попробуй, я сильно беспокоюсь из-за этой же ошибки и, наконец, изменил свою ссылку, и она отлично работала. Надеюсь, что это решит вашу проблему.
Ответ 3
У меня есть аналогичная настройка, и она отлично работает для меня.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/applicationContext-struts.xml", "classpath:/applicationContext.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public abstract class BaseTests {
Я предполагаю, что проблема заключается в настройке вашего проекта. Вы используете Eclipse? Загружает ли он файлы контекста из папки /bin или из папки /src? Вы исключали "applicationContext-security.xml" из сборки?
Ответ 4
Вам нужно сказать Spring, чтобы воздействовать на эти аннотации. В соответствующем файле контекста вы должны добавить следующее:
<context:annotation-config/>
Теперь он будет искать эти аннотации. См. Документацию Spring на Настройка на основе аннотаций
Чтобы ограничить количество классов, которые нужно сканировать, чтобы вы не просматривали пакеты без аутсорсинга, добавьте следующее:
<context:component-scan base-package="org.example"/>
Подробнее см. в документах для "Автоматическое обнаружение компонентов" , а также пространства имен XML, которое необходимо добавить для ссылки на эти теги.
Ответ 5
Каково имя bean для userDetailsService
в вашем xml? Возможно, вам потребуется добавить аннотацию @Qualifier
с именем bean, а затем помещать тег <qualifier>
в контекст.
Посмотрите Spring документация по этой теме.
Ответ 6
У меня такие же проблемы. Кажется, что вместо UserDataOnDemand существует прокси UserDataOnDemand.