如何对部署在 Tomcat 上的 Jersey Web 应用程序进行单元测试?
我正在构建一个部署在 Tomcat 上的 Jersey Web 应用程序.我很难理解如何对应用程序进行单元测试.
I'm building a Jersey web application deployed on Tomcat. I'm having a hard time understanding how to unit test the app.
只需在我的测试中实例化类并调用它们的方法(这与 Jersey 或 Tomcat 无关),就可以测试核心业务逻辑(非 Jersey 资源类).
Testing the core business logic (the non-Jersey-resource classes) is possible by simply instantiating the classes in my tests and calling methods on them (this has nothing to do with Jersey or Tomcat).
但是,对 Jersey 资源类(即映射到 URL 的类)进行单元测试的正确方法是什么?
But what is the right way to unit test the Jersey resource classes (i.e., the classes that map to URLs)?
我需要为此运行 Tomcat 吗?或者我应该模拟请求和响应对象,在我的测试中实例化资源类,然后将模拟提供给我的类?
Do I need to have Tomcat running for this? Or should I mock the request and response objects, instantiate the resource classes in my tests, and feed the mocks to my classes?
我在 Jersey 的网站上阅读了有关测试的信息,但他们在示例中使用的是 Grizzly 而不是 Tomcat,这是不同的.
I have read about testing in Jersey's site, but they're using Grizzly and not Tomcat in their examples, which is different.
请说明应该如何进行.欢迎使用示例代码.
Please explain how this should be done. Example code would be welcome.
推荐答案
如果你只想单元测试,不需要启动任何服务器.如果您有服务(业务层)或任何其他注入,例如 UriInfo
和类似性质的东西,您可以模拟.一个非常流行的模拟框架是 Mockito.下面是一个完整的例子
If you just want to unit test, there's no need to start any server. If you have an services (business layer) or any other injections like UriInfo
and things of that nature, you can just mock the. A pretty popular mocking framework is Mockito. Below is a complete example
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的实例
如果你想运行 integration 测试,我个人认为无论你是运行 Grizzly 容器还是运行 Tomcat 容器,只要你不使用应用程序中特定于 Tomcat 的任何内容.
If you want to run an integration test, personally I don't see much difference whether or not you are running a Grizzly container vs. running a Tomcat container, as long as you are not using anything specific to Tomcat in your application.
使用 Jersey 测试框架 是一个很好的集成选择测试,但他们没有 Tomcat 提供程序.只有 Grizzly、In-Memory 和 Jetty.如果您没有使用任何 Servlet API,例如 HttpServletRequest
或 ServletContext
等,则 In-Memory 提供程序可能是一个可行的解决方案.它会给你更快的测试时间.
Using the Jersey Test Framework is a good option for integration testing, but they do not have a Tomcat provider. There is only Grizzly, In-Memory and Jetty. If you are not using any Servlet APIs like HttpServletRequest
or ServletContext
, etc, the In-Memory provider may be a viable solution. It will give you quicker test time.
另请参阅:
- junit 4 test case to test rest web service除了文档中给出的示例之外的一些示例.
- junit 4 test case to test rest web service for some examples, aside from the ones given in the documentation.
如果您必须使用 Tomcat,您可以运行自己的嵌入式 Tomcat.我没有找到太多文档,但是在 DZone 中有一个 示例.我并没有真正使用嵌入式 Tomcat,但是按照上一个链接中的示例,您可以拥有类似以下的内容(已经过测试可以工作)
If you must use Tomcat, you can run your own embedded Tomcat. I have not found much documentation, but there is an example in DZone. I don't really use the embedded Tomcat, but going of the example in the previous link, you can have something like the following (which has been tested to work)
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"));
}
}
相关文章