簡體   English   中英

測試 JAX-RS Web 服務?

[英]Testing a JAX-RS Web Service?

我目前正在尋找為基於JAX-RS (RESTful Web 服務的 Java API)的 Web 服務創建自動化測試的方法。

我基本上需要一種方法來向它發送某些輸入並驗證我是否得到了預期的響應。 我更喜歡通過 JUnit 來做到這一點,但我不確定如何實現。

您使用什么方法來測試您的網絡服務?

更新:正如 entzik 所指出的,將 Web 服務與業務邏輯解耦允許我對業務邏輯進行單元測試。 但是,我還想測試正確的 HTTP 狀態代碼等。

Jersey帶有一個很棒的 RESTful 客戶端 API,可以讓編寫單元測試變得非常容易。 請參閱 Jersey 附帶的示例中的單元測試。 我們使用這種方法來測試Apache Camel 中的 REST 支持,如果您有興趣, 測試用例在這里

您可以試用REST Assured ,這使得測試 REST 服務和驗證 Java 響應變得非常簡單(使用 JUnit 或 TestNG)。

正如詹姆斯所說; Jersey 有內置的測試框架 一個簡單的 hello world 示例可以是這樣的:

用於 maven 集成的 pom.xml。 當你運行mvn test 框架啟動了一個灰熊容器。 您可以通過更改依賴項來使用 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>
...

示例應用程序.java

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/")
public class ExampleApp extends Application {

}

你好世界

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);
    }
}

您可以查看示例應用程序。

您可能編寫了一些實現業務邏輯的 Java 代碼,然后為它生成了 Web 服務端點。

要做的一件重要事情是獨立測試您的業務邏輯。 由於它是純 Java 代碼,因此您可以使用常規的 JUnit 測試來做到這一點。

現在,由於 Web 服務部分只是一個端點,您要確保生成的管道(存根等)與您的 Java 代碼同步。 您可以通過編寫調用生成的 Web 服務 java 客戶端的 JUnit 測試來做到這一點。 這將讓您知道何時更改 Java 簽名而不更新 Web 服務內容。

如果您的 Web 服務管道是由您的構建系統在每次構建時自動生成的,那么可能沒有必要測試端點(假設它全部正確生成)。 取決於你的偏執程度。

盡管從發布問題之日起為時已晚,但認為這可能對有類似問題的其他人有用。 Jersey 附帶了一個名為Jersey 測試框架測試框架,它允許您測試 RESTful Web 服務,包括響應狀態代碼。 您可以使用它在輕量級容器(如 Grizzly、HTTPServer 和/或 EmbeddedGlassFish)上運行測試。 此外,該框架還可用於在常規 Web 容器(如 GlassFish 或 Tomcat)上運行您的測試。

我使用 Apache 的HTTPClient (http://hc.apache.org/)來調用 Restful 服務。 HTTP 客戶端庫允許您輕松執行獲取、發布或您需要的任何其他操作。 如果您的服務使用 JAXB 進行 xml 綁定,您可以創建一個 JAXBContext 來序列化和反序列化來自 HTTP 請求的輸入和輸出。

看看Alchemy 休息客戶端生成器 這可以在幕后使用 jersey 客戶端為您的 JAX-RS web 服務類生成代理實現。 實際上,您將從單元測試中將 Web 服務方法稱為簡單的 java 方法。 也處理 http 身份驗證。

如果您需要簡單地運行測試,則不涉及代碼生成,因此很方便。

免責聲明:我是這個庫的作者。

把事情簡單化。 查看可以從 Maven Central 導入的https://github.com/valid4j/http-matchers

    <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...

一個重要的事情是獨立測試你的業務邏輯

我當然不會假設編寫 JAX-RS 代碼並希望對接口進行單元測試的人不知何故,出於某種奇怪的、莫名其妙的原因,不知道他或她可以對程序的其他部分進行單元測試,包括業務邏輯類。 陳述顯而易見的事情幾乎沒有幫助,而且人們反復強調響應也需要測試。

Jersey 和 RESTEasy 都有客戶端應用程序,在 RESTEasy 的情況下,您可以使用相同的注解(甚至排除帶注釋的接口並在測試的客戶端和服務器端使用)。

REST 不是這項服務能為您做什么; REST 你可以為這個服務做什么。

據我了解,此問題作者的主要目的是將 JAX RS 層與業務層分離。 並且單元測試只有第一個。 這里我們必須解決兩個基本問題:

  1. 在測試中運行一些 Web/應用程序服務器,將 JAX RS 組件放入其中。 而只有他們。
  2. 模擬 JAX RS 組件/REST 層內的業務服務。

第一個是用 Arquillian 解決的。 第二個在arquillican 和 mock 中得到了完美的描述

這是代碼示例,如果您使用其他應用程序服務器可能會有所不同,但我希望您能了解基本思想和優點。

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));
   }
}

一些注意事項:

  1. 此處使用不帶 web.xml 的 JAX RS 配置。
  2. 這里使用的是 JAX RS Client(沒有 RESTEasy/Jersey,它們暴露了更方便的 API)
  3. 當測試開始時,Arquillian 的運行程序開始工作。 在這里您可以找到如何使用所需的應用程序服務器為 Arquillian 配置測試。
  4. 根據所選的應用程序服務器,測試中的 url 會略有不同。 可以使用另一個端口。 Glassfish Embedded 在我的示例中使用了 8181。

希望,它會有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM