我尝试为ProductDAO
类运行JUnit测试用例,这是Spring Web应用程序的一部分。但它仍然失败。我不确定我的test-context.xml文件。
我在路径ProductDAOImplTest
中有src/test/java
个类,并且堆栈跟踪中提到的ProductController
类保存在路径src/main/java
中。
ProductDAOImplTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/test/resources/test-context.xml")
@Transactional
public class ProductDAOImplTest {
@Autowired
private ProductDAO productDAO;
@Test
public void testAdd() {
fail("Not yet implemented");
}
@Test
public void testEdit() {
fail("Not yet implemented");
}
@Test
public void testGetAll() {
fail("Not yet implemented");
}
@Test
public void testGet() {
fail("Not yet implemented");
}
@Test
public void testRemove() {
fail("Not yet implemented");
}
@Test
public void testGetByPage() {
fail("Not yet implemented");
}
}
测试context.xml中
<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:mvc="http://www.springframework.org/schema/mvc" 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.myapp" />
<context:annotation-config />
<!-- JDBC -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="file:src/main/webapp/WEB-INF/jdbc.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
<!-- Hibernate -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
堆栈跟踪
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:103)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:73)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'productController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.servlet.http.HttpServletRequest com.myapp.controller.ProductController.request; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [javax.servlet.http.HttpServletRequest] 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:288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1120)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:106)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:57)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
... 24 more
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.servlet.http.HttpServletRequest com.myapp.controller.ProductController.request; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [javax.servlet.http.HttpServletRequest] 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:514)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
... 40 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [javax.servlet.http.HttpServletRequest] 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:949)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:818)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:730)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
... 42 more
答案 0 :(得分:26)
错误在堆栈跟踪
中无法自动装配字段:private javax.servlet.http.HttpServletRequest com.myapp.controller.ProductController.request; ... 没有类型为[ javax.servlet.http.HttpServletRequest ]的匹配bean
问题在于,简单的Spring测试使用简单的Spring应用程序上下文运行,没有Spring Web Application上下文功能。因此,在这种情况下,HttpServletRequests,Servlet Context和其他功能不可用。
尝试将@WebAppConfiguration
注释添加到测试类中。
请注意,此选项仅适用于Spring 3.2+版本。
在旧版本的Spring中,你需要发明一些东西来使这个接口实现在应用程序上下文中可用(最直接的事情是将MockServletContext类和/或HttpServletRequest接口公开为测试的bean)。
另请注意,使用会话范围bean的代码通常是控制器特定的,属于web application context,我相信在使用@WebAppConfiguration
的单独测试中测试控制器是最佳做法,但是在简单的应用程序上下文中保留属于根应用程序上下文的普通旧bean和服务的测试,即没有@WebAppConfiguration
。
要明确ProductDAO
属于根应用程序上下文,ProductController
属于Web应用程序上下文,因此它们的定义应放在不同的xml文件中。 ProductDAO
测试应指向根应用程序上下文的xml 并且不包含@WebAppConfiguration
。
至于ProductController
测试应指向根应用程序上下文和Web应用程序上下文xml文件(请参阅How to Setup web application context in Spring MVC test示例)并使用@WebAppConfiguration
进行注释
答案 1 :(得分:8)
你目前正在做的事情很好,虽然我会说它更像是集成测试而不是单元测试。
我的主要建议是仅提供您测试中的组件绝对需要的系统部分,例如: ProductDAO
。
您似乎已经在某种程度上这样做了,但也可能有助于将component-scan
的范围缩小到您保留DAO的范围,例如:
<context:component-scan base-package="com.myapp.dao" />
这样可以避免使用控制器和服务等更高级别的组件。
然后,您可以将上下文重命名为test-dao-context.xml
,并在所有其他DAO测试中使用它。
当您对服务进行集成测试时,您可以使用test-service-context.xml
上下文导入test-dao-context.xml
,允许您从服务到数据库进行测试,而无需过多重复bean定义。
答案 2 :(得分:4)
您的单元测试设置让我(非常)紧张。您正在尝试引导所有内容,包括休眠,事务管理器和组件扫描。你几乎需要自己的容器才能做到这一点。
通常,良好的单元测试仅针对每个测试类的一个类,所有依赖项都使用诸如Mockito之类的库进行模拟
答案 3 :(得分:0)
我同意格里坦和乔纳森写的内容。我还建议您查看Springockito以便更轻松地进行模拟。