Java 测试JAX-RSWeb服务?

Java 测试JAX-RSWeb服务?,java,web-services,unit-testing,junit,jax-rs,Java,Web Services,Unit Testing,Junit,Jax Rs,我目前正在寻找为基于(RESTfulWeb服务的JavaAPI)的Web服务创建自动化测试的方法 我基本上需要一种方法来向它发送某些输入,并验证我是否得到了预期的响应。我更愿意通过JUnit实现这一点,但我不确定如何实现这一点 您使用什么方法来测试web服务 更新:正如entzik指出的那样,将web服务与业务逻辑分离允许我对业务逻辑进行单元测试。但是,我还想测试正确的HTTP状态码等。您可能编写了一些实现业务逻辑的java代码,然后为其生成了web服务端点 一件重要的事情是独立测试您的业务逻辑

我目前正在寻找为基于(RESTfulWeb服务的JavaAPI)的Web服务创建自动化测试的方法

我基本上需要一种方法来向它发送某些输入,并验证我是否得到了预期的响应。我更愿意通过JUnit实现这一点,但我不确定如何实现这一点

您使用什么方法来测试web服务


更新:正如entzik指出的那样,将web服务与业务逻辑分离允许我对业务逻辑进行单元测试。但是,我还想测试正确的HTTP状态码等。

您可能编写了一些实现业务逻辑的java代码,然后为其生成了web服务端点

一件重要的事情是独立测试您的业务逻辑。因为它是纯java代码,所以可以通过常规的JUnit测试来实现

现在,由于web服务部分只是一个端点,您需要确保生成的管道(存根等)与java代码同步。您可以通过编写JUnit测试来调用生成的web服务java客户端来实现这一点。当您在不更新web服务内容的情况下更改java签名时,这将让您知道


如果web服务管道是在每次生成时由生成系统自动生成的,那么可能不需要测试端点(假设所有端点都正确生成)。取决于您的偏执程度。

我使用Apache调用Restful服务。HTTP客户端库允许您轻松执行get、post或任何其他需要的操作。如果您的服务使用JAXB进行xml绑定,您可以创建一个JAXBContext来序列化和反序列化来自HTTP请求的输入和输出。

附带了一个非常好的RESTful客户端API,使编写单元测试变得非常容易。请参阅Jersey附带的示例中的单元测试。我们使用此方法测试中的REST支持,如果您对

感兴趣,尽管从发布问题之日起已经太晚了,但我们认为这可能对其他有类似问题的人有用。 Jersey附带了一个名为的测试框架,允许您测试RESTful Web服务,包括响应状态代码。您可以使用它在Grizzly、HTTPServer和/或EmbeddedGlassFish等轻量级容器上运行测试。此外,该框架还可用于在常规web容器(如GlassFish或Tomcat)上运行测试

一件重要的事情是独立测试您的业务逻辑

我当然不会假设编写JAX-RS代码并希望对接口进行单元测试的人不知何故,出于某种奇怪、无法解释的原因,忘记了他或她可以对程序的其他部分进行单元测试的概念,包括业务逻辑类。陈述显而易见的事实几乎没有什么帮助,人们反复强调,这些反应也需要测试

Jersey和RESTEasy都有客户端应用程序,在RESTEasy的情况下,您可以使用相同的注释(甚至可以去掉注释接口,并在测试的客户端和服务器端使用)


不要指望这项服务能为你做什么;休息一下你能为这项服务做些什么

您可以尝试使用Java(使用JUnit或TestNG)测试REST服务和验证响应,这非常简单。

正如James所说;泽西岛有内置的。一个简单的hello world示例如下:

用于maven集成的pom.xml。运行
mvn测试时
。框架启动一个灰色容器。您可以通过更改依赖项来使用jetty或tomcat

...
<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.16</version>
  </dependency>

  <dependency>
    <groupId>org.glassfish.jersey.test-framework</groupId>
    <artifactId>jersey-test-framework-core</artifactId>
    <version>2.16</version>
    <scope>test</scope>
  </dependency>

  <dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>2.16</version>
    <scope>test</scope>
  </dependency>
</dependencies>
...
HelloWorld.java

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/")
public final class HelloWorld {

    @GET
    @Path("/hello")
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHelloWorld() {

        return "Hello World!";
    }
}
HelloWorldTest.java

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.core.Application;
import static org.junit.Assert.assertEquals;

public class HelloWorldTest extends JerseyTest {

    @Test
    public void testSayHello() {

        final String hello = target("hello").request().get(String.class);

        assertEquals("Hello World!", hello);
    }

    @Override
    protected Application configure() {

        return new ResourceConfig(HelloWorld.class);
    }
}
您可以查看示例应用程序。

请查看。这可以在幕后使用jersey客户端为JAX-RSWebService类生成代理实现。实际上,您可以从单元测试中将webservice方法称为简单的java方法。处理http身份验证

如果您需要简单地运行测试,那么就不需要生成代码,这样做很方便


Dislclaimer:我是这个库的作者。

据我所知,这个问题的作者的主要目的是将JAX RS层与业务层解耦。而单元测试只是第一个。我们必须解决两个基本问题:

  • 在测试一些web/应用服务器时运行,将JAX-RS组件放入 信息技术只有他们
  • JAX-RS内部的模拟业务服务 组件/休息层
  • 第一个问题由Arquillian解决。 第二个在本文中得到了完美的描述

    下面是一个代码示例,如果您使用另一个应用程序服务器,可能会有所不同,但我希望您能了解其基本思想和优点

    import javax.inject.Inject;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    
    import com.brandmaker.skinning.service.SomeBean;
    
    /**
    * Created by alexandr on 31.07.15.
    */
    @Path("/entities")
    public class RestBean
    {
       @Inject
       SomeBean bean;
    
       @GET
       public String getEntiry()
       {
           return bean.methodToBeMoked();
       }
    }
    
    import java.util.Set;
    
    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    
    import com.google.common.collect.Sets;
    
    /**
    */
    @ApplicationPath("res")
    public class JAXRSConfiguration extends Application
    {
       @Override
       public Set<Class<?>> getClasses()
       {
           return Sets.newHashSet(RestBean.class);
       }
    }
    
    
    public class SomeBean
    {
       public String methodToBeMoked()
       {
           return "Original";
       }
    }
    
    import javax.enterprise.inject.Specializes;
    
    import com.brandmaker.skinning.service.SomeBean;
    
    /**
    */
    @Specializes
    public class SomeBeanMock extends SomeBean
    {
       @Override
       public String methodToBeMoked()
       {
           return "Mocked";
       }
    }
    
    @RunWith(Arquillian.class)
    public class RestBeanTest
    {
       @Deployment
       public static WebArchive createDeployment() {
           WebArchive war = ShrinkWrap.create(WebArchive.class, "test.war")
                   .addClasses(JAXRSConfiguration.class, RestBean.class, SomeBean.class, SomeBeanMock.class)
                   .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
           System.out.println(war.toString(true));
           return war;
       }
    
       @Test
       public void should_create_greeting() {
           Client client = ClientBuilder.newClient();
           WebTarget target = client.target("http://127.0.0.1:8181/test/res/entities");
           //Building the request i.e a GET request to the RESTful Webservice defined
           //by the URI in the WebTarget instance.
           Invocation invocation = target.request().buildGet();
           //Invoking the request to the RESTful API and capturing the Response.
           Response response = invocation.invoke();
           //As we know that this RESTful Webserivce returns the XML data which can be unmarshalled
           //into the instance of Books by using JAXB.
           Assert.assertEquals("Mocked", response.readEntity(String.class));
       }
    }
    
    import javax.inject.inject;
    导入javax.ws.rs.GET;
    导入javax.ws.rs.Path;
    导入com.brandmaker.skining.service.SomeBean;
    /**
    *由alexandr于2015年7月31日创建。
    */
    @路径(“/实体”)
    公共类RestBean
    {
    @注入
    豆豆;
    @得到
    公共字符串getEntry()
    {
    return bean.methodToBemoke();
    }
    }
    导入java.util.Set;
    导入javax.ws.rs.ApplicationPath;
    导入javax.ws.rs.core.Application;
    导入com.google.common.collect.set;
    /**
    */
    @应用程序路径(“res”)
    公共类JAXRSConfiguration扩展了应用程序
    {
    @凌驾
    
    公共设置保持简单。看看哪些可以从Maven Central导入

        <dependency>
            <groupId>org.valid4j</groupId>
            <artifactId>http-matchers</artifactId>
            <version>1.0</version>
        </dependency>
    

    你说得很对,虽然我还需要测试返回的实际HTTP响应,特别是HTTP状态码。re:现在坏链接你可以找到jersey/samples中提到的示例,这些示例显示单元测试,基本上是通过jersey的消费者使用web资源。这个项目在GitHub上,在src/te中查找测试st folder:我不怀疑这个答案,但我觉得非常有趣的是,Jersey总是进入JAX-RS对话,而在某些情况下(不幸的是,确切地说是WebSphere)它不可用并重新启动
        <dependency>
            <groupId>org.valid4j</groupId>
            <artifactId>http-matchers</artifactId>
            <version>1.0</version>
        </dependency>
    
    // Statically import the library entry point:
    import static org.valid4j.matchers.http.HttpResponseMatchers.*;
    
    // Invoke your web service using plain JAX-RS. E.g:
    Client client = ClientBuilder.newClient();
    Response response = client.target("http://example.org/hello").request("text/plain").get();
    
    // Verify the response
    assertThat(response, hasStatus(Status.OK));
    assertThat(response, hasHeader("Content-Encoding", equalTo("gzip")));
    assertThat(response, hasEntity(equalTo("content")));
    // etc...