0

当我从其他应用程序调用时,有一个休息 Web 服务可以正常工作,但是当我从 Junit 测试程序调用时它会失败。在过去的几个小时里我读了很多书,如果我理解正确,主题中的错误发生有两个可能的原因:1 - 当我使用 MockMvc 时,它忽略了 JNDI 和 2 - 类路径中没有所需的 jar . 关于罐子,我认为这不是原因,因为当从其他应用程序调用时它确实运行正常。关于 jndi,我很困惑为什么容器可以在从其他应用程序调用 web 服务时提供数据源,但在从模拟测试器调用时失败。我发现的最接近的问题是如何使用 Spring 测试模拟的 JNDI 数据源?. 在这个线程中,最后一条评论似乎给出了一个很好的解决方案,但我无法实现主要是因为没有带有“jee:jndi-lookup”的 jndi 文件定义。简而言之,其余 Web 服务是一个公开方法的控制器,并且在该方法内部有一个获取连接的地方。超出控制范围的一切我都不允许更改。如何使用 MockMvc 测试这个 REST 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));

//test-mvc-dispatcher-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)
4

1 回答 1

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()

    }

}
于 2014-12-23T01:52:10.350 回答