2008-09-23 102 views
71

我正在尋找方法爲JAX-RS(基於REST風格的Web服務的Java API)基於Web服務創建自動化測試。單元測試JAX-RS Web服務?

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

你用什麼方法來測試你的web服務?

更新:正如entzik指出的那樣,將Web服務從業務邏輯中分離出來,使我能夠對業務邏輯進行單元測試。但是,我也想測試正確的HTTP狀態代碼等。

+5

好問題 - 但是我會說,如果你是通過HTTP測試,然後這讓我感到這是集成測試。 – 2011-05-03 14:46:03

+0

湯姆。你是絕對正確的。我們應該爲此注入一個虛擬HTTP模擬器/輕量級容器。在node.js世界supertest使這個。你可以模擬express.js。 – 2015-02-25 18:38:12

回答

35

Jersey附帶一個很好的RESTful客戶端API,使得編寫單元測試非常簡單。請參閱Jersey附帶的示例中的單元測試。我們使用這種方法在Apache Camel測試REST支持,如果你有興趣的test cases are here

+6

回覆:現在不好鏈接 你可以在澤西/樣本中找到顯示單元測試的例子,基本上是使用澤西的消費者來消費網絡資源。 http://download.java.net/maven/2/com/sun/jersey/samples/bookstore/1.1.5-ea-SNAPSHOT – rogerdpack 2009-11-09 19:55:42

+3

再次連接不良 - 請介意更新? – 2015-07-10 19:19:28

+2

這個項目在GitHub上,在src/test文件夾中找到測試:https://github.com/jersey/jersey/tree/master/examples/bookstore-webapp – Venkat 2016-03-24 15:01:53

5

您可能寫了一些實現您的業務邏輯的java代碼,然後爲其生成了Web服務端點。

要做的重要事情是獨立測試您的業務邏輯。由於它是純Java代碼,因此您可以使用常規的JUnit測試來完成此操作。

現在,由於Web服務部分只是一個終點,您要確保生成的管道(存根等)與您的java代碼同步。你可以通過編寫調用生成的Web服務Java客戶端的JUnit測試來實現這一點。這會讓你知道什麼時候改變你的java簽名而不更新web服務的東西。

如果您的Web服務管道是由您的構建系統在每個構建中自動生成的,則可能不需要測試端點(假設它已全部正確生成)。取決於你的偏執狂水平。

+1

雖然我也需要測試返回的實際HTTP響應,特別是HTTP狀態代碼,但您說得很對。 – Einar 2008-09-25 10:58:14

3

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

6

雖然它可以發佈問題的日期太晚了,認爲這可能是其他人誰也有類似的問題非常有用。 Jersey帶有一個名爲Jersey Test Framework的測試框架,它允許您測試RESTful Web服務,包括響應狀態代碼。您可以使用它來在像Grizzly,HTTPServer和/或EmbeddedGlassFish這樣的輕量級容器上運行測試。此外,該框架可用於在GlassFish或Tomcat等常規Web容器上運行測試。

2

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

我當然不會認爲誰寫的JAX-RS碼和人正在尋求單元測試接口在某種程度上是出於某種奇怪的,不可理解的原因,忘記了他或她可以單元測試程序的其他部分(包括業務邏輯類)的概念。陳述這些顯而易見的事情並沒有什麼幫助,而且反覆提出的觀點也需要進行測試。

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

REST不是這個服務可以爲你做什麼; REST你可以爲這項服務做些什麼。

22

您可以試用REST Assured,這使得它很容易簡單測試REST服務和驗證Java中的響應(使用JUnit或TestNG)。正如詹姆斯所說的那樣:

10

澤西島內置test framework。一個簡單的Hello World例子可以是這樣的:

pom.xml用於maven集成。當你運行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> 
... 

ExampleApp.java

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

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

} 

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

您可以檢查this示例應用程序。

3

看看Alchemy rest client generator。這可以在場景後面使用平臺客戶端爲您的JAX-RS webservice類生成代理實現。實際上,您將從單元測試中將您的webservice方法作爲簡單的java方法調用。還處理http身份驗證。

如果您需要簡單地運行測試以便於使用,則不涉及代碼生成。

免責聲明:我是該圖書館的作者。

1

據我所知,這個問題的作者的主要目的是分離JAX RS層與商業之一。而單元測試只有第一個。兩個基本問題下面我們就來解決:在測試

  1. 運行某些Web /應用程序服務器,把JAX RS組件 它。只有他們。
  2. JAX RS 組件/ REST層中的模擬業務服務。

第一個問題是用Arquillian解決的。 在arquillican and 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. JAX RS配置,而web.xml文件在這裏使用。
  2. JAX RS客戶端在這裏使用(沒有RESTEasy/Jersey,他們公開更方便的API)
  3. 當測試開始時,Arquillian的跑步者開始工作。 Here你可以找到如何爲所需的應用服務器配置Arquillian測試。
  4. 根據所選的應用程序服務器, 測試中的網址會有所不同。可以使用另一個端口。 8181是 在我的例子中被Glassfish Embedded使用。

希望它能幫上忙。

2

保持簡單。看看可以從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...