如何测试Jersey REST Web服务?

18

我已经编写了一个Restful Web服务,并且使用了Jersey Client编写了客户端,现在想知道是否可以仅使用JUnit4来测试我的服务。是否有人能提供至少一个示例帮助我。

我的Rest服务具有authenticate方法,该方法接受用户名、密码并返回令牌。

我已经为authenticate方法编写了测试用例,但不确定如何使用URL进行测试。

public class TestAuthenticate {
    Service service  = new Service();
    String username = "user";
    String password = "password";
    String token;

    @Test(expected = Exception.class)
    public final void testAuthenticateInputs() {
        password = "pass";
        service.authenticate(username, password);
    }

    @Test(expected = Exception.class)
    public final void testAuthenticateException(){
        username = null;
        String token = service.authenticate(username, password);
        assertNotNull(token);
    }

    @Test
    public final void testAuthenticateResult() {
        String token = service.authenticate(username, password);
        assertNotNull(token);
    }
}

1
如果您想使用URL进行测试,则需要从测试中启动服务器。您可以使用嵌入式服务器,这在测试中非常常见。或者您可以利用Jersey测试框架,它将为您启动一个嵌入式容器。您正在使用哪个版本的Jersey? - Paul Samsotha
请查看此问题,它解释了如何使用Mockito模拟您的Web服务。 - Daniel Gomez Rico
3个回答

24

如果您想使用URL进行测试,则需要从测试中启动服务器。您可以显式地启动嵌入式服务器,这在测试中非常常见。例如:

public class MyResourceTest {

    public static final String BASE_URI = "http://localhost:8080/api/";
    private HttpServer server;

    @Before
    public void setUp() throws Exception {
        final ResourceConfig rc = new ResourceConfig(Service.class);
        server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);       
    }

    @After
    public void tearDown() throws Exception {
        server.stop();
    }

    @Test
    public void testService() {
        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(BASE_URI).path("service");
        ...
    }
}

这基本上是一项集成测试。您将启动Grizzly容器,并将一个只包含Service类的ResourceConfig加载到服务器中。当然,您可以向配置中添加更多的类。如果您想要,您可以使用“真实”的资源配置。

上述测试使用了这个依赖项。

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-grizzly2-http</artifactId>
    <version>${jersey2.version}</version>
</dependency>

另一个选项(我更喜欢的那个)是使用Jersey测试框架,它将为您启动嵌入式容器。测试可能看起来会更像:

public class SimpleTest extends JerseyTest {
 
    @Override
    protected Application configure() {
        return new ResourceConfig(Service.class);
    }
 
    @Test
    public void test() {
        String hello = target("service").request().get(String.class);
    }
}

使用此依赖

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

在幕后,将使用您的 ResourceConfig 配置启动嵌入式 Grizzly 容器。在上面的两个示例中,假设 Service 类的 @Path 值为 service,正如您在测试 URL 中看到的那样。

一些资源

一些示例


更新

如果您不使用 Maven,则需要以下 jar 包才能运行用于 Jersey 测试框架的嵌入式 Grizzly 容器

enter image description here

我通常在这里搜索所有我的 jar 包。您可以选择版本,下一页应该有一个下载链接。您可以使用搜索栏搜索其他jar包。

一旦您拥有了所有的jar包,这是一个简单的运行示例

import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.spi.container.servlet.WebComponent;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import junit.framework.Assert;
import org.junit.Test;

public class SimpleTest extends JerseyTest {
    
    @Path("service")
    public static class Service {
        @GET
        public String getTest() { return "Hello World!"; }
    }

    public static class AppConfig extends DefaultResourceConfig {
        public AppConfig() {
            super(Service.class);
        }
    }
    
    @Override
    public WebAppDescriptor configure() {
        return new WebAppDescriptor.Builder()
                .initParam(WebComponent.RESOURCE_CONFIG_CLASS, 
                           AppConfig.class.getName())
                .build();
    }
    
    @Test
    public void doTest() {
        WebResource resource = resource().path("service");
        String result = resource.get(String.class);
        Assert.assertEquals("Hello World!", result);
        System.out.println(result);
    }
}

很可能您不会在测试中使用ResourceConfig类及其资源,但我只是想保持简单,让所有内容都在一个类中可见。

无论您使用web.xml还是ResourceConfig子类(如上所示),都可以通过在测试类中构建一个单独的ResourceConfig来缩小测试范围,就像我所做的那样。否则,如果您正在使用正常的ResourceConfig类,则可以在configure方法中替换它。

configure方法基本上就是用Java代码构建web.xml文件。您可以看到WebAppDescriptor.Builder中的不同方法,例如initParam,它与web xml中的<init-param>相同。您可以仅使用参数中的字符串,但也有一些常量,就像我上面使用的那样。

@Test是您通常运行的JUnit测试。它使用Jersey客户端。但是,您可以直接访问resource()方法以使用预配置的Client,而不是创建Client。如果您熟悉Jersey客户端,则此类对您来说应该不陌生。


所以,现在我明白了,要访问Rest Web服务,我们必须使用JerseyTest框架或Rest Assured框架以及Junit(非必需),而不能仅使用Junit。如果我有误,请纠正我。 - Jenny
你可以以与在Tomcat服务器上运行Jersey应用程序相同的方式,通过在测试开始时启动嵌入式服务器来在测试中运行Jersey应用程序,并在测试完成后停止它。这就是我在第一个示例中所做的,也是Jersey测试框架在幕后为您完成的。这是通过JUnit完成的。一旦所有测试都完成了,服务器就会停止。 - Paul Samsotha
我可以帮助您入门,但我需要更多信息。例如,您使用的Jersey版本以及是否使用Maven。我上面的答案假设您正在使用Maven。如果不是,我可以帮助您找到所需的jar文件以使其运行起来。 - Paul Samsotha
谢谢。我正在使用Jersey 1.19,目前我们没有使用Maven。(虽然我们可能会使用gradle)。现在我的要求是使用Jersey测试框架、Junit 4和Jmock。(如果有意义的话)。 - Jenny
1
非常好的解释,实现的设置文档和完美的答案。谢谢你。我甚至不知道Jersey有一个内置的服务器容器可以作为模拟测试配置进行调用。这使得测试简单服务方法以获得测试覆盖率变得容易。 - Clint L
显示剩余9条评论

0

我认为@peeskillet已经给了你所需的前提条件,即你需要在嵌入式Web服务器中运行你的Web服务。你也可以考虑使用Dropwizard或Spring Boot支持来方便地完成这个过程。

至于实际验证响应,我会保持简单,并使用JUnit和http-matchers(请参见https://github.com/valid4j/http-matchers)。


0

看一下Alchemy rest client generator。它可以使用jersey客户端在后台为您的JAX-RS webservice类生成代理实现。有效地,您将从单元测试中调用您的webservice方法作为简单的java方法。还可以处理http身份验证。

如果您只需要运行测试,则无需进行代码生成,因此非常方便。

这里的演示设置了grizzly并使用上面的生成器来运行junit测试。

免责声明:我是这个库的作者。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接