Java Spring单元测试和初始化上下文

Java Spring单元测试和初始化上下文,java,spring,unit-testing,spring-mvc,tomcat,Java,Spring,Unit Testing,Spring Mvc,Tomcat,我想在Tomcat和Spring4运行的情况下进行一个简单的集成测试,注入一个Spring组件,并使用Tomcat现有的数据源配置。我不想配置我的数据源两次。 所有内容,包括我的数据源,都在文件WebContent/WEB-INF/application context.xml中配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"

我想在Tomcat和Spring4运行的情况下进行一个简单的集成测试,注入一个Spring组件,并使用Tomcat现有的数据源配置。我不想配置我的数据源两次。 所有内容,包括我的数据源,都在文件
WebContent/WEB-INF/application context.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" xmlns:task="http://www.springframework.org/schema/task"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                http://www.springframework.org/schema/data/jpa      http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/jee           http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">

    <task:annotation-driven />

    <!-- annotations in bean classes -->
    <!-- context:annotation-config / -->

    <!-- mvc:annotation-driven / -->
    <context:component-scan base-package="com.mycompany.package.**" />

    <jpa:repositories base-package="com.mycompany.package.**" />


    <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        <property name="jpaDialect" ref="jpaDialect" />
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceUnitName" value="packagePU" />
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
        </property>
        <property name="jpaPropertyMap">
            <props>
                <prop key="eclipselink.weaving">false</prop>
            </props>
        </property>
    </bean>

    <bean id="jpaVendorAdapter"
        class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
        <property name="generateDdl" value="false" />
        <property name="showSql" value="true" />
    </bean>

    <bean id="jpaDialect"
        class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
    <!-- <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> 
        <property name="validationMessageSource" ref="messageSource"/> </bean> -->

    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames" value="i18n/messages" />
    </bean>

    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/DefaultDB" />

</beans>
目前,我在运行测试时遇到此错误

java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in URL [file:WebContent/WEB-INF/application-context.xml]: Cannot resolve reference to bean 'dataSource' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': 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
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': 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
...
Caused by: 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
...

我完全理解需要一个InitialContext,但是如何使用Tomcat提供的上下文(包括数据源配置)提供测试?我不想设置两次数据源连接凭据。

解决了这个问题。简单回顾一下问题:Spring尝试创建
dataSource
bean,但无法查找JNDI名称,因为没有可用的JNDI

因此,为了进行测试,我只创建了另一个XML文件,覆盖bean
dataSource
。我忽略了版本控制中的文件,并要求每个开发人员将此文件复制到位:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="com.sap.db.jdbc.Driver"
        p:url="jdbc:sap://xxx:30015"
        p:username="sa"
        p:password="">
    </bean>

</beans>

解决了。简单回顾一下问题:Spring尝试创建
dataSource
bean,但无法查找JNDI名称,因为没有可用的JNDI

因此,为了进行测试,我只创建了另一个XML文件,覆盖bean
dataSource
。我忽略了版本控制中的文件,并要求每个开发人员将此文件复制到位:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="com.sap.db.jdbc.Driver"
        p:url="jdbc:sap://xxx:30015"
        p:username="sa"
        p:password="">
    </bean>

</beans>
为这个问题提供了一个舒适的解决方案。它基于Tomcat的JNDI系统,只初始化Tomcat的JNDI环境而不启动服务器。因此,您可以在测试中或从任何JavaSE应用程序中访问Tomcat配置文件中配置的所有资源。用法很简单,例如。g

TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processContextXml(contextXmlFile);
tomcatJNDI.start();

DataSource ds = (DataSource) InitialContext.doLookup("java:comp/env/path/to/datasource");
为这个问题提供了一个舒适的解决方案。它基于Tomcat的JNDI系统,只初始化Tomcat的JNDI环境而不启动服务器。因此,您可以在测试中或从任何JavaSE应用程序中访问Tomcat配置文件中配置的所有资源。用法很简单,例如。g

TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processContextXml(contextXmlFile);
tomcatJNDI.start();

DataSource ds = (DataSource) InitialContext.doLookup("java:comp/env/path/to/datasource");

能否粘贴您正在使用的application-context.xml?如果是大的,只需粘贴相关部分。根据我的理解,您可以在xml中拥有所有内容,而不需要两次指定数据源。您不需要进行任何初始化。我有工作代码,我从来没有这个problem@user3659052我已经添加了内容,谢谢您没有参考您的数据源。做两件事。第一个更改:第二个更改:添加或定义数据源所需的任何内容。那么这个错误就会消失away@user3659052正如您所看到的,两者都已经存在(除了您提到的预期类型,但给出了相同的错误)。对于第二个更改,请查看entityManagerFactory,我在其中引用了在同一文件中定义的数据源。我没有使用DAOs。除了测试外,该web应用程序运行良好。由于缺少初始上下文,它看起来更像是无法创建bean“dataSource”。您可以粘贴您正在使用的application-context.xml吗?如果是大的,只需粘贴相关部分。根据我的理解,您可以在xml中拥有所有内容,而不需要两次指定数据源。您不需要进行任何初始化。我有工作代码,我从来没有这个problem@user3659052我已经添加了内容,谢谢您没有参考您的数据源。做两件事。第一个更改:第二个更改:添加或定义数据源所需的任何内容。那么这个错误就会消失away@user3659052正如您所看到的,两者都已经存在(除了您提到的预期类型,但给出了相同的错误)。对于第二个更改,请查看entityManagerFactory,我在其中引用了在同一文件中定义的数据源。我没有使用DAOs。除了测试外,该web应用程序运行良好。看起来它实际上无法创建bean“数据源”由于缺少初始上下文。假设您使用的是maven,请将其放入
src/test/resources
中,您不应该手动复制文件。但我不希望将我的凭据放在源代码存储库中。然后将凭据放在文件系统(主目录)中每个用户的属性文件中。此外,如果是为了测试,为什么拥有它们会如此危险,那么您应该为此拥有一个测试帐户,而不是您自己的帐户或生产帐户。让开发人员复制某些东西以进行测试或其他方式很容易出错,最终会对您造成伤害。假设您使用的是maven,请将其放入
src/test/resources
中,您不应该手动复制文件。但我不希望将凭据放在源代码存储库中。然后将凭据放在是文件系统(主目录)上的每个用户。此外,如果是为了测试,为什么拥有它们会如此危险,那么您应该为此拥有一个测试帐户,而不是您自己的帐户或生产帐户。让开发人员在适当的地方复制一些东西以进行测试或其他方式是容易出错的,最终会让您感到痛苦。