spring - 如何在内存中进行单元测试 Spring-Jersey

标签 spring unit-testing junit jersey jersey-2.0

我正在使用 Spring-Jersey3,但无法弄清楚如何使用 Spring bean 对 RESTFul API 进行单元测试

Controller

package com.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.service.DataSource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("test")
@Component
public class SpringController {
    @Autowired
    private DataSource datasource;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getHello() {
        return new String(datasource.load());
    }
}

服务接口(interface)
package com.service;

public interface DataSource {
    public String load();
}

服务实现
package com.service;

import org.springframework.stereotype.Repository;

@Repository
public class DataSourceImpl implements DataSource {

    @Override
    public String load() {
        return "Hello";
    }
}

ResourceRegister.java(泽西资源寄存器)
package com.component;

import org.glassfish.jersey.server.ResourceConfig;
import com.controller.SpringController;

public class ResourceRegister extends ResourceConfig {

    public ResourceRegister () {
        register(SpringController.class);
    }
}

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:applicationContext.xml</param-value>
</context-param>

<servlet>
  <servlet-name>Jersey</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
  <param-name>javax.ws.rs.Application</param-name>
  <param-value>com.component.ResourceRegister</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>Jersey</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

serviceContext.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:context="http://www.springframework.org/schema/context"
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">

<context:component-scan base-package="com.service" />
<context:component-scan base-package="com.controller" />

</beans>

单元测试<<--我真的不知道如何测试这个
public class test extends JerseyTest {
    public test() {
        super("com.service", "com.controller");
    }

    @Override
    protected AppDescriptor configure() {
        return new WebAppDescriptor.Builder("com.service","com.controller")
               .contextParam("contextConfigLocation", "classpath:serviceContext.xml")
               .contextPath("/rest")
               .servletClass("org.glassfish.jersey.servlet.ServletContainer.class")
               .initParam("javax.ws.rs.Application", "com.component.ResourceRegister")
               .build();
    }

    @Test
    public void test() {
        Client client = new Client();
        WebResource resource = client.resource("test");

        ClientResponse response = resource.post(ClientResponse.class);

        assertEquals(200, resposne.getStatus());
    }
}

项目 Source Code

问题:依赖注入(inject)返回 null

最佳答案

我要解决的一些问题:

  • 您正在使用 Jersey 1.x 风格的 Jersey 测试框架,但您的应用是 Jersey 2.x。请参阅下面的 2.x 依赖项。
  • 我从未使用过 Jersey 1.x 风格的测试框架,但使用 Jersey 2.x,In-Memory container不支持 servlet 依赖的特性。有关不同的依赖关系,请参见下文。
  • 使用 Jersey 测试框架,您不需要创建 Client你自己。创建了一个,我们可以简单地调用JerseyTesttarget(String path)取回 WebTarget 的方法(泽西 2.x,WebResource 是泽西 1.x)

  • 这是一个有效的重构。

    依赖项(我只添加了这个依赖项,并没有删除任何内容,因为您的 GitHub 项目不包含任何与测试相关的内容,就像您上面的代码示例一样)
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
        <version>2.15</version>
    </dependency>
    

    测试
    import com.component.ResourceRegister;
    import org.glassfish.jersey.servlet.ServletContainer;
    import org.glassfish.jersey.test.DeploymentContext;
    import org.glassfish.jersey.test.JerseyTest;
    import org.glassfish.jersey.test.ServletDeploymentContext;
    import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
    import org.glassfish.jersey.test.spi.TestContainerFactory;
    import org.junit.Assert;
    import org.junit.Test;
    import org.springframework.web.context.ContextLoaderListener;
    
    public class SpringTest extends JerseyTest {
    
        @Override
        protected TestContainerFactory getTestContainerFactory() {
            return new GrizzlyWebTestContainerFactory();
        }
    
        @Override
        protected DeploymentContext configureDeployment(){
            return ServletDeploymentContext
                    .forServlet(new ServletContainer(new ResourceRegister()))
                    .addListener(ContextLoaderListener.class)
                    .contextParam("contextConfigLocation", "classpath:applicationContext.xml")
                    .build();
        }
    
        @Test
        public void test() {
            String response = target("test").request().get(String.class);
            Assert.assertEquals("Hello", response);
            System.out.println(response);
        }  
    }
    

    对于那些不使用 xml 上下文文件的人,您可以使用注释配置应用程序上下文,并将其添加为 init 参数
    return ServletDeploymentContext
            .forServlet(new ServletContainer(new ResourceRegister()))
            .addListener(ContextLoaderListener.class)
            .initParam("contextConfig", new AnnotationConfigApplicationContext(YourSpringConfig.class))
            .build();
    

    其他资源:
  • Jersey Test Framework Documentation
  • More examples from Test Framework source code tests . (提示:我提供的链接是针对 grizzly Web 容器示例的,但是如果您返回到 providers,您可以查看每个提供程序并转到测试包以获取这些提供程序的示例)


  • 更新

    所以经过几次测试后,我发现了一些有趣的事情

    一:

    有了上面的依赖,即使我们不配置DeploymentContext , 并覆盖 Application configure()JerseyTest ,它仍然可以工作。无法真正解释它,但似乎描述符仍然被拾取。
    import javax.ws.rs.core.Application;
    import org.glassfish.jersey.server.ResourceConfig;
    import org.glassfish.jersey.test.JerseyTest;
    import org.junit.Assert;
    import org.junit.Test;
    
    public class SpringTest extends JerseyTest {
    
        @Override
        public Application configure() {
            return new ResourceConfig().packages("com.controller");
        }
    
        @Test
        public void test() {
            String response = target("test").request().get(String.class);
            Assert.assertEquals("Hello", response);
            System.out.println(response);
        }  
    }
    

    二:

    即使我们摆脱了上述依赖(grizzly)并使用内存中的依赖,同样简单的先前测试仍然有效。该文件指出

    In-Memory container is not a real container. It starts Jersey application and directly calls internal APIs to handle request created by client provided by test framework. There is no network communication involved. This containers does not support servlet and other container dependent features, but it is a perfect choice for simple unit tests.



    所以我不完全确定他们指的是什么 Servlet 功能,因为这个测试仍然有效
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-inmemory</artifactId>
        <version>2.15</version>
    </dependency>
    

    我特别不明白的是这个声明

    "There is no network communication involved"



    因为当我运行测试时,我看到了一个日志

    INFO: Creating InMemoryTestContainer configured at the base URI http://localhost:9998/

    关于spring - 如何在内存中进行单元测试 Spring-Jersey,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28614846/

    相关文章:

    java - 如何在 Spring JPA for MySQL 中为 @Id @GeneratedValue 设置初始值?

    .net - 我如何允许实现使用自己的参数调用 Mock (Moq) 方法?

    java - 使用自定义测试运行程序的参数化测试

    c# - NUnit 2016 抛出.TypeOf

    java - 使用本地镜像测试 URI

    java - 无法从客户端 x509 证书中检索主体

    java - 如何在 Spring 非 EE 应用程序中注入(inject) infinispan 缓存?

    spring - Spring JPA 存储库 save() 有时会进行更新吗?

    java - 无法通过长 ID 删除实体

    java - Kotlin 中 @BeforeAll 的正确解决方法是什么