java Spring JUnit 测试用例失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17619029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring JUnit test case failed
提问by misco
I try to run a JUnit test case for ProductDAO
class, that is part of the spring web application. But it still fails. I am not sure by my test-context.xml file.
我尝试为ProductDAO
类运行 JUnit 测试用例,它是 Spring Web 应用程序的一部分。但它仍然失败。我不确定我的 test-context.xml 文件。
I have ProductDAOImplTest
class in path src/test/java
and mentioned ProductController
class in the stacktrace is saved in a path src/main/java
.
我ProductDAOImplTest
在路径src/test/java
中有ProductController
类,并且堆栈跟踪中提到的类保存在路径中src/main/java
。
ProductDAOImplTest
产品DAOImplTest
@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");
}
}
test-context.xml
测试上下文.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>
Stacktrace
堆栈跟踪
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.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.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access<context:component-scan base-package="com.myapp.dao" />
0(ParentRunner.java:53)
at org.junit.runners.ParentRunner.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.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
回答by Boris Treukhov
The error is in the stack trace
错误在堆栈跟踪中
Could not autowire field: private javax.servlet.http.HttpServletRequestcom.myapp.controller.ProductController.request; ... No matching bean of type [javax.servlet.http.HttpServletRequest]
无法自动装配字段:私有javax.servlet.http.HttpServletRequestcom.myapp.controller.ProductController.request; ... 没有匹配的 [ javax.servlet.http.HttpServletRequest] 类型的 bean
The problem is that simple Spring tests run with the bare Spring apprlication context, without Spring Web Application context capabilities. So HttpServletRequests, Servlet Context and other features are not available in this case.
问题是简单的 Spring 测试使用裸 Spring 应用程序上下文运行,没有 Spring Web 应用程序上下文功能。所以 HttpServletRequests、Servlet Context 等特性在这种情况下是不可用的。
Try adding @WebAppConfiguration
annotation to the test class.
尝试向@WebAppConfiguration
测试类添加注释。
Please note, that this option is available only in Spring 3.2+ versions.
请注意,此选项仅在 Spring 3.2+ 版本中可用。
In the older versions of Spring you'll need to invent something to make this interface implementations available in the application context(the most straightforward thing is to expose MockServletContext class and/or HttpServletRequest interface as beans for tests).
在旧版本的 Spring 中,您需要发明一些东西来使这个接口实现在应用程序上下文中可用(最直接的事情是将 MockServletContext 类和/或 HttpServletRequest 接口公开为用于测试的 bean)。
Also please note that the code that uses session scope beans is usually controller specific and belongs to web application contextand I believe that it will be the best practice to test controllers in separate tests with the @WebAppConfiguration
, but leave the tests of the plain old beans and services belonging to the root application context in the simple application contexts, i.e. without @WebAppConfiguration
.
另请注意,使用会话范围 bean 的代码通常是特定于控制器的,属于Web 应用程序上下文,我相信在单独的测试中使用 测试控制器将是最佳实践@WebAppConfiguration
,但保留普通旧 bean 的测试和属于简单应用程序上下文中的根应用程序上下文的服务,即没有@WebAppConfiguration
.
Just to be clear ProductDAO
belongs to the root application context, and ProductController
belongs to the web application context, so their definitions should be placed in different xml files. ProductDAO
test should point to the xml of the root app context onlyand contain no @WebAppConfiguration
.
需要说明的是,ProductDAO
属于根应用上下文,ProductController
属于web应用上下文,所以它们的定义应该放在不同的xml文件中。ProductDAO
test 应该只指向根应用程序上下文的 xml并且不包含@WebAppConfiguration
.
As for ProductController
test should point to both root app context and web app context xml files (see How to Setup web application context in Spring MVC testfor examples) and be annotated with @WebAppConfiguration
至于ProductController
测试应该同时指向根应用程序上下文和 web 应用程序上下文 xml 文件(有关示例,请参阅如何在 Spring MVC 测试中设置 web 应用程序上下文)并使用注释 @WebAppConfiguration
回答by Jonathan
What you are doing currently is fine, although I would say it is more of an integration test than a unit test.
您目前正在做的事情很好,尽管我会说它更像是集成测试而不是单元测试。
My main suggestion would be to only bring up parts of the system that you absolutely need for the component under test, e.g. the ProductDAO
.
我的主要建议是只调出被测组件绝对需要的系统部分,例如ProductDAO
.
You already seem to be doing this to a certain extent but what may also help is reducing the scope of your component-scan
to where you keep your DAOs, e.g.:
您似乎已经在一定程度上这样做了,但也可能有帮助的是将您的范围缩小component-scan
到您保留 DAO 的位置,例如:
This would avoid picking up higher-level components such as Controllers and Service.
这将避免选择更高级别的组件,例如控制器和服务。
You could then rename the context to test-dao-context.xml
and use it in all your other DAO tests.
然后,您可以将上下文重命名为test-dao-context.xml
并在所有其他 DAO 测试中使用它。
When you come to integration testing your Services you could then have a test-service-context.xml
context which imports test-dao-context.xml
allowing you to test from the service to the database without too much repetition of bean definitions.
当您开始集成测试您的服务时,您可以拥有一个test-service-context.xml
导入的上下文,test-dao-context.xml
允许您从服务到数据库进行测试,而无需过多重复 bean 定义。
回答by gerrytan
Your unit test setup make me (very) nervous. You're trying to bootstrap everything including hibernate, transaction manager and component scanning. You almost need your own container to do this.
你的单元测试设置让我(非常)紧张。您正在尝试引导一切,包括休眠、事务管理器和组件扫描。您几乎需要自己的容器来执行此操作。
Typically a good unit test focuses on one class only per test class, all its dependencies are mocked using libraries such as Mockito
通常,一个好的单元测试只关注每个测试类的一个类,它的所有依赖项都使用 Mockito 之类的库进行模拟
回答by MarcelK
I agree with what gerrytan and Jonathan wrote. I'd also suggest taking a look at Springockitofor easier mocking.
我同意 gerrytan 和 Jonathan 所写的。我还建议查看Springockito以便更轻松地模拟。