当我从其他应用程序唤起时,有一个休息的Web服务工作正常但是当我从Junit测试器唤起时它失败了。我在最后几个小时读了很多,如果我理解正确的话,主题中的错误发生了两个可能的原因:1 - 当我使用MockMvc时它忽略了JNDI和2 - 没有类路径中需要的jar 。关于jar,我不认为它可能是原因,因为它从其他应用程序调用时确实正确运行。关于jndi,我很困惑为什么容器可以在从其他应用程序调用web服务时提供数据源但在从模拟测试器调用时失败。我发现的最接近的问题是How to test a mocked JNDI datasource with Spring?。在这个帖子中,似乎最后的评论提供了一个很好的解决方案,但我无法实现主要是因为没有jndi文件定义与“jee:jndi-lookup”。简而言之,其余的Web服务是一个暴露方法的控制器,在这个方法中有一个获取连接的地方。超出控制器的一切都不允许改变。如何使用MockMvc测试此休息Web服务?当从模拟测试器中唤起其他服务时,为什么锁定不起作用?有没有办法在test-mvc-dispatcher-servlet.xml中添加一些配置来使“ic.lookup(”java:comp / env / jdbc / MHE“)”运行?
//连接是从这个方法提供的,我无法改变它
public Connection getConnection()throws Exception{
try{
InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/MHE"); //the error happens here
//休息网络服务
@Controller
@RequestMapping("/log")
public class Lo_Controller {
@Autowired
private Mhe_Handler mhe_Handler; //now Autowired
@Autowired
private Lo_Mas60010 lo_Mas60010;
@Autowired
private LogDisplay testReturn;
@ExceptionHandler(Exception.class)
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="Contact not found")
public void notFound() {
System.out.println("error ...");
}
@RequestMapping(value="display/last", method=RequestMethod.POST)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public LogDisplay getFirst(@RequestBody Mas60010 mas60010) {
Connection con; // it is the only object not Autowired inside the Controler but take a note that the error happens inside mhe_Handler.getConnection()
try {
con = mhe_Handler.getConnection();
// MockMvc
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath:/com/myCompany/mhe/test/test-mvc-dispatcher-servlet.xml")
public class RestErrorHandlingTest {
@Autowired
private WebApplicationContext wac;
@Autowired
private LogDisplay logDisplay;
@Autowired
private Mas60010 _mas60010;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void postLog() throws Exception {
Mas60010 _mas60010 = new Mas60010(
... the parameters here, not relevant information
);
ObjectMapper mapper = new ObjectMapper();
this.mockMvc.perform(
post("/log/display/last")
.contentType(
new MediaType(
MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8")
)
)
.content(mapper.writeValueAsBytes(_mas60010))
)
.andExpect(status().isBadRequest())
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andExpect(model().attribute("logDisplay", logDisplay));
//测试-MVC-调度-servlet.xml中
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config />
<mvc:annotation-driven />
<context:component-scan base-package="com.myCompany.mhe.common.controller, com.myCompany.mhe.log.handler, com.myCompany.mhe.utilities, com.myCompany.mhe.log.domain" />
<context:property-placeholder location="classpath:restServices.properties"/>
<mvc:resources mapping="/**" location="/" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
</beans>
//错误日志
Dec 23, 2014 8:19:29 AM org.springframework.test.context.support.AbstractTestContextBootstrapper getDefaultTestExecutionListenerClassNames
INFO: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
Dec 23, 2014 8:19:29 AM org.springframework.test.context.support.AbstractTestContextBootstrapper instantiateListeners
INFO: Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource]
Dec 23, 2014 8:19:29 AM org.springframework.test.context.support.AbstractTestContextBootstrapper instantiateListeners
INFO: Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute]
Dec 23, 2014 8:19:29 AM org.springframework.test.context.support.AbstractTestContextBootstrapper getTestExecutionListeners
INFO: Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@4a738d08, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@68302e67, org.springframework.test.context.support.DirtiesContextTestExecutionListener@3336a1a1]
Dec 23, 2014 8:19:30 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [com/myCompany/mhe/test/test-mvc-dispatcher-servlet.xml]
Dec 23, 2014 8:19:31 AM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO: Overriding bean definition for bean 'logDisplay': replacing [Generic bean: class [com.myCompany.mhe.log.domain.LogDisplay]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\STS\wsRestTemplate\MHE_original\WebContent\WEB-INF\classes\com\myCompany\mhe\log\domain\LogDisplay.class]] with [Generic bean: class [com.myCompany.mhe.log.domain.LogDisplay]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [com/myCompany/mhe/test/test-mvc-dispatcher-servlet.xml]]
Dec 23, 2014 8:19:31 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.web.context.support.GenericWebApplicationContext@68a53de4: startup date [Tue Dec 23 08:19:31 CST 2014]; root of context hierarchy
Dec 23, 2014 8:19:32 AM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [restServices.properties]
Dec 23, 2014 8:19:32 AM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Dec 23, 2014 8:19:32 AM org.springframework.web.servlet.handler.AbstractHandlerMethodMapping registerHandlerMethod
INFO: Mapped "{[/log/display/last],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public com.myCompany.mhe.log.domain.LogDisplay com.myCompany.mhe.common.controller.Lo_Controller.getFirst(com.myCompany.mhe.log.domain.Mas60010)
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Dec 23, 2014 8:19:33 AM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter initControllerAdviceCache
INFO: Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@68a53de4: startup date [Tue Dec 23 08:19:31 CST 2014]; root of context hierarchy
Dec 23, 2014 8:19:33 AM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter initControllerAdviceCache
INFO: Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@68a53de4: startup date [Tue Dec 23 08:19:31 CST 2014]; root of context hierarchy
Dec 23, 2014 8:19:33 AM org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/**] onto handler 'org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0'
Dec 23, 2014 8:19:33 AM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter initControllerAdviceCache
INFO: Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@68a53de4: startup date [Tue Dec 23 08:19:31 CST 2014]; root of context hierarchy
Dec 23, 2014 8:19:58 AM org.springframework.mock.web.MockServletContext log
INFO: Initializing Spring FrameworkServlet ''
Dec 23, 2014 8:19:58 AM org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet '': initialization started
Dec 23, 2014 8:19:58 AM org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet '': initialization completed in 183 ms
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 javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.myCompany.mhe.Mhe_Handler.getConnection(Mhe_Handler.java:40)
at com.myCompany.mhe.common.controller.Lo_Controller.getFirst(Lo_Controller.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:595)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:144)
at com.myCompany.mhe.test.RestErrorHandlingTest.postLog(RestErrorHandlingTest.java:151)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:217)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
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:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
答案 0 :(得分:0)
您的控制器不是可测试的。依赖项Mhe_Handler
在方法getFirst
中被实例化为局部变量,因此无法在单元测试中模拟它。一种解决方案是将其作为私有字段提取并自动装配,这是依赖注入最重要的好处之一:
class Controller {
//inject real Mhe_Handler backed by jndi datasource in production
//while inject mockups in unit test
@Autowired private Mhe_Handler mhe_Handler;
public LogDisplay getFirst() {
//inject dependency instead of hard-wire it
mhe_Handler.getConnection()
}
}