【问题标题】:Failed to load ApplicationContext in JUnit with JNDI datasource使用 JNDI 数据源在 JUnit 中加载 ApplicationContext 失败
【发布时间】:2014-03-17 17:43:49
【问题描述】:

我在测试我的应用程序时遇到了一些麻烦,但它在正常执行时运行良好。 我认为它来自未找到的 JNDI 资源,但我不明白为什么以及如何修复它。

当我开始我的 Junit 测试时,我收到了这个错误:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
    at ...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'DAOImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource com.sample.DAOImpl.myDatasource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] 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), @org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDatasource' defined in URL [file:src/test/resources/spring/test-dao-config.xml]: Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
    at ...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource com.sample.DAOImpl.myDatasource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] 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), @org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
    at ...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] 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), @org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
    at ..

这是我的配置:

Context.xml

<Resource name="jdbc/myDatasource" auth="Container" type="javax.sql.DataSource"
    driverClassName="oracle.jdbc.OracleDriver"
    url="jdbc:oracle:thin:@database:99999:instance"
    username="user"
    password="password"
    validationQuery="select 1 from dual"
    testOnBorrow ="true"
    maxActive="5"
    maxIdle="1"
    maxWait="-1" />

test-dao-config.xml

<bean id="myDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/myDatasource" />
</bean>

DaoImpl

@Repository
public class DacsDAOImpl implements DacsDAO
{
    private final static Logger LOGGER = LoggerFactory.getLogger(DAOImpl.class);

    @Autowired
    @Qualifier("myDatasource")
    private DataSource myDatasource;

    ....
}

还有我的测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/test/resources/spring/test-dao-config.xml" })
public class MyDAOImplTest
{
    private MyDAO dao;

    @BeforeClass
    public static void initJndi() throws IllegalStateException, NamingException
    {
        //some test, but doesn't work

//      SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
//      builder.bind("java:comp/env/jdbc/myDatasource", "myDatasource");
//      builder.activate();
    }

    @Before
    public void setUp() throws IllegalStateException, NamingException
    {
        dao = new MyDAOImpl();
    }

    @Test
    public void testTotalUser()
    {
        int result = dao.getTotalUser();
        Assert.assertEquals(0, result);
    }
}

谢谢

【问题讨论】:

  • 请发布堆栈跟踪的其余部分。

标签: spring spring-mvc junit jndi spring-junit


【解决方案1】:

您正在测试用例中运行,因此 Context.xml 中的所有内容均不可用,因为仅在 tomcat 上可用。为什么你需要在你的测试用例中进行 jndi 查找呢?如果您想测试您的 dao,请使用内存数据库(如 hsql、h2 或 derby)并改用它。 Spring 有一些不错的标签可以让您轻松使用。

<jdbc:embedded-database id="myDataSource" type="H2">
    // Add some init scripts here.
</jdbc:embedded-database>

如果您真的需要进行 JNDI 查找,那么您的测试用例就差不多完成了。但是,您必须注册 DataSource 而不是 String。所以你仍然需要构建一些(内存中的)数据源并将其绑定到模拟 jndi 位置

@BeforeClass
public static void initJndi() throws IllegalStateException, NamingException
{
    //some test, but doesn't work
    // Construct in-memory database
  SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
  builder.bind("java:comp/env/jdbc/myDatasource", myDatasource);  //Actual datasource not a String!
  builder.activate();
}

最后你的测试也有缺陷,你正在加载你的上下文,但没有对它做任何事情。您正在 @Before 方法中构建 MyDAOImpl。为什么还要费心加载上下文,因为你什么都不做。

【讨论】:

  • 其实datasource是daoImpl的一个autowired属性。而且我知道有像 H2 这样的嵌入式数据库,我接下来会使用它,但我想让我的测试在添加我还不知道的东西之前工作
  • 那行不通。正如我已经提到的,您没有可用的 JNDI。除非您从 context.xml 复制配置,否则您将无法连接到您的实际数据库,配置一个实际的 DataSource 指向您的实际数据库。然后您必须使用SimpleNamingContextBuilder 将其添加到您的模拟 JNDI 树中。
  • 我终于用嵌入式数据库做到了,因为它看起来比 jndi 简单
猜你喜欢
  • 2011-07-26
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 2020-08-23
  • 2012-09-14
  • 1970-01-01
  • 2018-07-03
相关资源
最近更新 更多