如何对部署在Tomcat上的Jersey web应用程序进行单元测试



我正在构建一个部署在Tomcat上的Jersey web应用程序。我很难理解如何对应用程序进行单元测试。

通过简单地实例化测试中的类并调用它们上的方法(这与Jersey或Tomcat无关),就可以测试核心业务逻辑(非Jersey资源类)。

但是,对Jersey资源类(即映射到URL的类)进行单元测试的正确方法是什么?

为此,我需要运行Tomcat吗?或者我应该模拟请求和响应对象,实例化测试中的资源类,并将模拟提供给我的类?

我在Jersey的网站上读到过关于测试的内容,但他们在示例中使用的是Grizzly,而不是Tomcat,这是不同的。

请解释应该如何做到这一点。欢迎使用示例代码。

如果您只想单元测试,就不需要启动任何服务器。如果您有一个服务(业务层)或任何其他注入,如UriInfo和类似性质的东西,您可以模拟。Mockito是一个非常流行的嘲讽框架。以下是的完整示例

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
/**
 * Beside Jersey dependencies, you will need Mockito.
 * 
 *  <dependency>
 *      <groupId>org.mockito</groupId>
 *      <artifactId>mockito-core</artifactId>
 *      <version>1.10.19</version>
 *  </dependency>
 * 
 * @author Paul Samsotha
 */
public class SomethingResourceUnitTest {
    public static interface SomeService {
        String getSomethingById(int id);
    }
    @Path("something")
    public static class SomethingResource {
        private final SomeService service;
        @Inject
        public SomethingResource(SomeService service) {
            this.service = service;
        }
        @GET
        @Path("{id}")
        public Response getSomethingById(@PathParam("id") int id) {
            String result = service.getSomethingById(id);
            return Response.ok(result).build();
        }
    }
    private SomethingResource resource;
    private SomeService service;
    @Before
    public void setUp() {
        service = Mockito.mock(SomeService.class);
        resource = new SomethingResource(service);
    }
    @Test
    public void testGetSomethingById() {
        Mockito.when(service.getSomethingById(Mockito.anyInt())).thenReturn("Something");
        Response response = resource.getSomethingById(1);
        assertThat(response.getStatus(), is(200));
        assertThat(response.getEntity(), instanceOf(String.class));
        assertThat((String)response.getEntity(), is("Something"));
    }
}

另请参阅:

  • 如何获取javax.ws.rs.core.UriInfo的实例

如果您想运行集成测试,我个人认为,无论您是在运行Grizzly容器还是在运行Tomcat容器,只要您在应用程序中没有使用任何特定于Tomcat的东西,都没有太大区别。

使用Jersey测试框架是集成测试的一个很好的选择,但它们没有Tomcat提供程序。只有《灰熊》、《记忆中》和《杰蒂》。如果您不使用任何Servlet API,如HttpServletRequestServletContext等,内存中提供程序可能是一个可行的解决方案。它会给你更快的测试时间。

另请参阅:

  • 除了文档中给出的示例外,junit4测试用例还测试了一些rest web服务

如果必须使用Tomcat,则可以运行自己的嵌入式Tomcat。我没有找到太多的文档,但在DZone中有一个例子。我并没有真正使用嵌入式Tomcat,但从上一个链接中的例子来看,您可以使用类似以下的东西(经过测试可以工作)

import java.io.File;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
/**
 * Aside from the Jersey dependencies, you will need the following
 * Tomcat dependencies.
 * 
 *  <dependency>
 *      <groupId>org.apache.tomcat.embed</groupId>
 *      <artifactId>tomcat-embed-core</artifactId>
 *      <version>8.5.0</version>
 *      <scope>test</scope>
 *  </dependency>
 *  <dependency>
 *      <groupId>org.apache.tomcat.embed</groupId>
 *      <artifactId>tomcat-embed-logging-juli</artifactId>
 *      <version>8.5.0</version>
 *      <scope>test</scope>
 *  </dependency>
 *
 * See also https://dzone.com/articles/embedded-tomcat-minimal
 *      
 * @author Paul Samsotha
 */
public class SomethingResourceTomcatIntegrationTest {
    public static interface SomeService {
        String getSomethingById(int id);
    }
    public static class SomeServiceImpl implements SomeService {
        @Override
        public String getSomethingById(int id) {
            return "Something";
        }
    }
    @Path("something")
    public static class SomethingResource {
        private final SomeService service;
        @Inject
        public SomethingResource(SomeService service) {
            this.service = service;
        }
        @GET
        @Path("{id}")
        public Response getSomethingById(@PathParam("id") int id) {
            String result = service.getSomethingById(id);
            return Response.ok(result).build();
        }
    }
    private Tomcat tomcat;
    @Before
    public void setUp() throws Exception {
        tomcat = new Tomcat();
        tomcat.setPort(8080);
        final Context ctx = tomcat.addContext("/", new File(".").getAbsolutePath());
        final ResourceConfig config = new ResourceConfig(SomethingResource.class)
                .register(new AbstractBinder() {
                    @Override
                    protected void configure() {
                        bind(SomeServiceImpl.class).to(SomeService.class);
                    }
                });
        Tomcat.addServlet(ctx, "jersey-test", new ServletContainer(config));
        ctx.addServletMapping("/*", "jersey-test");
        tomcat.start();
    }
    @After
    public void tearDown() throws Exception {
        tomcat.stop();
    }
    @Test
    public void testGetSomethingById() {
        final String baseUri = "http://localhost:8080";
        final Response response = ClientBuilder.newClient()
                .target(baseUri).path("something").path("1")
                .request().get();
        assertThat(response.getStatus(), is(200));
        assertThat(response.readEntity(String.class), is("Something"));
    }
}

最新更新