如何使用 Jersey 2 测试框架为此 class 编写单元测试

How to write Unit Test for this class using Jersey 2 test framework

我正在尝试为 Rest api 调用编写单元测试,该调用具有使用 Jersey2 将视频文件添加到基于 Web 的应用程序的 POST 方法。这是我要为其编写单元测试的 class(TemplateController.java) 方法的签名:

@POST
@Path("/video/add")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response addVideoData(
    @Context HttpServletRequest request, 
    AttachmentDTO attachmentDTO) {
        ...
}

下面是我的测试方法 class (TemplateControllerUnitTestCase.java):

@Test
public void videoAdd_requestObjectIsNull_ResponseStatusIsOK() throws Exception {
    // arrange
    Builder builder = target("/target/video/add").request();
    // action
    final Response response = builder.post(Entity.entity(attachemntDTO, MediaType.APPLICATION_JSON));
    // assertion
    ...
}

我能够将 AttachmentDAO 对象从测试 class 传递到 TemplateController class 但无法传递在method(addVideoData())TemplateController.java class.

我正在使用 RequestHelper class,它是 HttpServletRequest 的助手 class,所以我想将此 class 的对象传递给method(addVideoData()) 使用 Jersey2 测试框架。

您可以将 HK2 capabilities of Jersey 2, that helps with Dependency Injection. Doing it this way, you can create a Factory 用于 HttpServletRequest 和 return 来自您的 RequestHelper 的模拟。例如

public class HttpServletRequestFactory implements Factory<HttpServlet> {

    @Override
    public HttpServletRequest provide() {
       return RequestHelper.getMockServletRequest();
    }

    @Override
    public void dispose(HttpSession t) {
    }
}

然后在您的 JerseyTest 子类中,只需用 ResourceConfig 注册一个 AbstractBinder。例如

@Override
public Application configure() {
    ResourceConfig config = new ResourceConfig(...);
    config.register(new AbstractBinder(){
        @Override
        public void configure() {
            bindFactory(HttpServletRequestFactory.class).to(HttpServletRequest.class);
        }
    });
} 

另一种选择

...根本不模拟 HttpServletRequest,而是使用实际的 HttpServletRequest。为此,我们需要在覆盖 getDeploymentContext() 和 return 和 ServletDeploymentContext 时配置 DeploymentContext。你可以看一个例子 and 。第一个还有一个使用 Factory 的示例,而第二个显示了如何根据 web.xml 设置进行配置的示例。如果您选择模拟 HttpServletRequest 的情况,那么您 将不会 需要覆盖 getTestContainerFactoryconfigureDeployment,如示例中所示。只需使用 Application configure() 覆盖就足够了,只要没有其他依赖于 servlet 功能。

link中的例子使用

<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey.version}</version>
</dependency>

额外

我 link 编辑的两个示例都试图利用 Sevlet 功能。所以我将给出一个使用请求模拟的完整示例。

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Assert;
import org.junit.Test;

public class MockHttpSevletRequestTest extends JerseyTest {

    @Path("http")
    public static class HttpResource {
        @GET
        public Response getResponse(@Context HttpServletRequest request) {
            return Response.ok(request.getMethod()).build();
        }
    }

    @Override
    public Application configure() {
        ResourceConfig config = new ResourceConfig(HttpResource.class);
        config.register(new AbstractBinder() {
            @Override
            public void configure() {
                bindFactory(HttpServletRequestFactory.class)
                        .to(HttpServletRequest.class);
            }
        });
        return config;
    }

    public static class HttpServletRequestFactory implements Factory<HttpServletRequest> {

        @Override
        public HttpServletRequest provide() {
            return new MockHttpServletRequest();
        }

        @Override
        public void dispose(HttpServletRequest t) {
        }
    }

    @Test
    public void test() {
        String response = target("http").request().get(String.class);
        System.out.println(response);
        Assert.assertEquals("POST", response);
    }
}

MockHttpServletRequestHttpServletRequest 的简单虚拟实现,其中我只重写一个方法 getMethod() 并且总是 return POST。你可以从结果中看到,即使它是一个 get 请求,它仍然 returns POST

public class MockHttpServletRequest implements HttpServletRequest {

    @Override
    public String getMethod() {
        return "POST";
    }
    ...
}