尝试对 DAO 类进行单元测试时,SessionFactory 没有自动装配
Posted
技术标签:
【中文标题】尝试对 DAO 类进行单元测试时,SessionFactory 没有自动装配【英文标题】:SessionFactory not getting autowired while trying to Unit test a DAO class 【发布时间】:2012-12-07 05:04:24 【问题描述】:我陷入了一种奇怪的情况,当我将我定义的 sessionFactory 作为 Web 应用程序运行时,它会自动连接到 DAO 类。
但是,当我尝试对这个 DAO 类进行单元测试时,spring 不会将 sessionFactory 自动装配到 DAO 类并引发以下异常。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'activityDAO': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.hibernate.SessionFactory com.adwitiya.vdb.data.activity.ActivityDAO.sessionFactory; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] 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:287) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:609) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:469) at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:84) at com.adwitiya.vdb.data.activity.ActivityDAOTest.testConstructor(ActivityDAOTest.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164) at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110) at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175) at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68) Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.hibernate.SessionFactory com.adwitiya.vdb.data.activity.ActivityDAO.sessionFactory; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] 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$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:506) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284) ... 41 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] 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.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:952) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:821) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478) ... 43 more
我已经做了很多谷歌搜索,但找不到解决这个问题的方法。如果您能帮助我,我将非常高兴和感激。
这是我的配置和类文件。
Web.xml
-------
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/vdb-data.xml
</param-value>
</context-param>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>vdb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>vdb</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list>
</web-app>
我的主要 MVC 配置文件如下。
vdb-servlet.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<mvc:resources mapping="/skin/**" location="/skin/" />
<context:annotation-config />
<context:component-scan base-package="com.adwitiya.vdb" />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:annotation-driven />
</beans>
下面是数据库相关的spring配置文件
vdb-data.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<context:property-placeholder location="classpath:database.properties" />
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="$database.driver" />
<property name="url" value="$database.url" />
<property name="username" value="$database.user" />
<property name="password" value="$database.password" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.adwitiya.vdb.domain" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">$hibernate.dialect</prop>
<prop key="hibernate.show_sql">$hibernate.show_sql</prop>
<prop key="hibernate.c3p0.min_size">$hibernate.c3p0.min_size</prop>
<prop key="hibernate.c3p0.max_size">$hibernate.c3p0.max_size</prop>
<prop key="hibernate.c3p0.timeout">$hibernate.c3p0.timeout</prop>
<prop key="hibernate.c3p0.max_statements">$hibernate.c3p0.max_statements</prop>
<prop key="hibernate.c3p0.idle_test_period">$hibernate.c3p0.idle_test_period</prop>
</props>
</property>
</bean>
<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
DAO 类
ActivityDAO
-----------
package com.adwitiya.vdb.data.activity;
import com.adwitiya.vdb.domain.Activity;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository("activityDAO")
public class ActivityDAO
@Autowired
private SessionFactory sessionFactory;
private Session session;
private boolean status;
private static Logger logger = Logger.getLogger(ActivityDAO.class);
public ActivityDAO()
try
session = sessionFactory.getCurrentSession();
catch(Exception exception)
logger.error(("Unable to initiate session because of the problem " + exception.getMessage()));
public boolean add(Activity activity)
try
logger.info("Trying to add an activity " + activity.toString());
session.save(activity);
status = true;
logger.info("Added the activity " + activity.toString() + " successfully");
catch(HibernateException exception)
logger.error("Couldn't add an activity " + activity.toString() + " because of the problem " + exception.getMessage());
catch(Exception exception)
logger.error("Couldn't add an activity " + activity.toString() + " because of the problem " + exception.getMessage());
return status;
public boolean modify(Activity activity)
try
logger.info("Trying to modify the activity " + activity.toString());
session.saveOrUpdate(activity);
status = true;
logger.info("Updated the activity " + activity.toString() + "successfully");
catch(HibernateException exception)
logger.error("Couldn't modify the activity " + activity.toString() + " because of the problem " + exception.getMessage());
catch(Exception exception)
logger.error("Couldn't modify the activity " + activity.toString() + " because of the problem " + exception.getMessage());
return status;
public boolean delete(Activity activity)
try
logger.info("Trying to delete the activity " + activity.toString());
session.delete(activity);
status=true;
logger.info("Deleted the activity " + activity.toString() + " successfully");
catch(HibernateException exception)
logger.error("Couldn't delete the activity " + activity.toString() + " because of the problem " + exception.getMessage());
catch(Exception exception)
logger.error("Couldn't delete the activity " + activity.toString() + " because of the problem " + exception.getMessage());
return status;
public SessionFactory getSessionFactory()
return sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory)
this.sessionFactory = sessionFactory;
public Session getSession()
return session;
public void setSession(Session session)
this.session = session;
public boolean isStatus()
return status;
public void setStatus(boolean status)
this.status = status;
最后是 ActivityDAOTest 类
ActivityDAOTest
---------------
package com.adwitiya.vdb.data.activity;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration( locations = "classpath:vdb-servlet.xml", "classpath:vdb-data.xml")
public class ActivityDAOTest
public ActivityDAOTest()
@Test
public void testConstructor()
Session thisSession = new Configuration().configure().buildSessionFactory().openSession();
ApplicationContext appcontext = new AnnotationConfigApplicationContext("com.adwitiya.vdb");
ActivityDAO activityDAO = (ActivityDAO) appcontext.getBean("ActivityDAO");
Session session = activityDAO.getSession();
assertEquals(thisSession,session);
【问题讨论】:
我想说的是,您所做的是集成测试,而不是单元测试。当我们对 Spring bean 进行单元测试时,我们会单独测试它们,即没有容器 - 并手动提供依赖项。 好的..你能告诉我应该怎么做吗? 不要在 integration 测试中手动创建 AnnotationConfigApplicationContext,而应按照 Benoit 的建议使用 Spring Test Context 框架。也不明白 thisSession 应该做什么,但没关系,因为使用@RunWith(SpringJUnit4ClassRunner.class)
是显而易见的选择。
好的,谢谢。我会浏览一些材料并尝试找到一种方法。
【参考方案1】:
您需要配置 JUnit 以便使用注解支持 Spring 注入:
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
然后你可以自动装配你的 DAO 来测试它:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( locations = "classpath:vdb-servlet.xml", "classpath:vdb-data.xml")
public class ActivityDAOTest
@Autowired
private ActivityDAO activityDAO;
@Test
public void testConstructor()
activityDAO.methodTotest();
【讨论】:
谢谢伙计……它似乎确实有帮助……但是又出现了一些错误:) 将尝试一次解决一件事..以上是关于尝试对 DAO 类进行单元测试时,SessionFactory 没有自动装配的主要内容,如果未能解决你的问题,请参考以下文章