Kiểm tra một Dịch vụ Web JAX-RS?


84

Tôi hiện đang tìm cách tạo các bài kiểm tra tự động cho dịch vụ web dựa trên JAX-RS (Java API cho RESTful Web Services).

Về cơ bản, tôi cần một cách để gửi cho nó một số đầu vào nhất định và xác minh rằng tôi nhận được phản hồi mong đợi. Tôi muốn làm điều này thông qua JUnit, nhưng tôi không chắc làm thế nào để đạt được điều đó.

Bạn sử dụng cách tiếp cận nào để kiểm tra các dịch vụ web của mình?

Cập nhật: Như entzik đã chỉ ra, việc tách dịch vụ web khỏi logic nghiệp vụ cho phép tôi kiểm tra đơn vị logic nghiệp vụ. Tuy nhiên, tôi cũng muốn kiểm tra mã trạng thái HTTP chính xác, v.v.


6
Câu hỏi hay - tuy nhiên tôi muốn nói rằng nếu bạn đang thử nghiệm qua HTTP thì tôi thấy rằng đây là thử nghiệm tích hợp.
Tom Duckering

Tom. Bạn hoàn toàn đúng. Chúng ta nên chèn một trình giả lập HTTP giả / vùng chứa nhẹ cho việc này. Trong node.js world supertest thực hiện điều này. Bạn có thể mô phỏng express.js.
Fırat KÜÇÜK

Câu trả lời:


34

Jersey đi kèm với một API máy khách RESTful tuyệt vời giúp việc viết các bài kiểm tra đơn vị trở nên thực sự dễ dàng. Xem các bài kiểm tra đơn vị trong các ví dụ đi kèm với Jersey. Chúng tôi sử dụng phương pháp này để kiểm tra hỗ trợ REST trong Apache Camel , nếu bạn quan tâm, các trường hợp kiểm tra có ở đây


6
re: now bad link Bạn có thể tìm thấy các ví dụ được đề cập trong jersey / mẫu hiển thị các bài kiểm tra đơn vị, về cơ bản bằng cách sử dụng người tiêu dùng của jersey để sử dụng tài nguyên web. download.java.net/maven/2/com/sun/jersey/samples/bookstore/…
rogerdpack

2
Dự án này nằm trên GitHub, hãy tìm các bài kiểm tra trong thư mục src / test: github.com/jersey/jersey/tree/master/examples/bookstore-webapp
Venkat,

2
Tôi không nghi ngờ câu trả lời này, nhưng tôi thấy vô cùng buồn cười khi Jersey luôn tìm cách tham gia vào cuộc trò chuyện JAX-RS, khi trong một số trường hợp (chính xác là WebSphere) nó không có sẵn và hiển thị 99% tất cả các câu trả lời có thể chấp nhận được trên Stack Overflow vô hiệu.

26

Bạn có thể dùng thử REST Assured , giúp kiểm tra các dịch vụ REST và xác thực phản hồi trong Java (sử dụng JUnit hoặc TestNG) rất đơn giản.


1
Tôi đã bỏ phiếu lên bài viết của bạn gây ra các thư viện nhìn tốt, nhưng họ chắc chắn sử dụng rất nhiều lọ phụ thuộc ...
Perry Tew

17

Như James đã nói; Có sẵn khung kiểm tra cho Jersey. Một ví dụ đơn giản về hello world có thể như sau:

pom.xml để tích hợp maven. Khi bạn chạy mvn test. Các khuôn khổ bắt đầu một vùng chứa hoa râm. Bạn có thể sử dụng cầu tàu hoặc tomcat thông qua việc thay đổi các phụ thuộc.

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

Ví dụApp.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);
    }
}

Bạn có thể kiểm tra ứng dụng mẫu này .


Với Jersey 2.29.1, tôi phải thêm jersey-hk2làm phụ thuộc vì tôi java.lang.IllegalStateException: InjectionManagerFactorygặp lỗi không tìm thấy (Xem câu hỏi này ). Nếu không, ví dụ này hoạt động tốt.
Sarah N

7

Bạn có thể đã viết một số mã java thực hiện logic nghiệp vụ của mình và sau đó bạn đã tạo điểm kết thúc dịch vụ web cho nó.

Một điều quan trọng cần làm là kiểm tra logic nghiệp vụ của bạn một cách độc lập. Vì đó là mã java thuần túy nên bạn có thể làm điều đó với các bài kiểm tra JUnit thông thường.

Bây giờ, vì phần dịch vụ web chỉ là điểm kết thúc, điều bạn muốn đảm bảo là hệ thống ống nước được tạo (sơ khai, v.v.) đồng bộ với mã java của bạn. bạn có thể làm điều đó bằng cách viết các bài kiểm tra JUnit gọi các máy khách java dịch vụ web đã tạo. Điều này sẽ cho bạn biết khi bạn thay đổi chữ ký java của mình mà không cần cập nhật nội dung dịch vụ web.

Nếu hệ thống xây dựng của bạn tự động tạo hệ thống ống nước của dịch vụ web, thì có thể không cần kiểm tra các điểm cuối (giả sử tất cả đều được tạo đúng cách). Phụ thuộc vào mức độ hoang tưởng của bạn.


2
Bạn hoàn toàn đúng, mặc dù tôi cũng cần kiểm tra các phản hồi HTTP thực tế được trả về, cụ thể là các mã trạng thái HTTP.
Einar

6

Mặc dù đã quá muộn kể từ ngày đăng câu hỏi, tôi nghĩ rằng điều này có thể hữu ích cho những người khác có câu hỏi tương tự. Jersey đi kèm với một khung thử nghiệm được gọi là Khung thử nghiệm Jersey cho phép bạn kiểm tra Dịch vụ Web RESTful của mình, bao gồm các mã trạng thái phản hồi. Bạn có thể sử dụng nó để chạy thử nghiệm của mình trên các vùng chứa nhẹ như Grizzly, HTTPServer và / hoặc EmbeddedGlassFish. Ngoài ra, khung có thể được sử dụng để chạy các thử nghiệm của bạn trên một vùng chứa web thông thường như GlassFish hoặc Tomcat.


Bạn có một ví dụ điển hình về cách chế nhạo các trình xử lý cuộc gọi không? JerseyHttpCall -> MyResource -> CallHandler.getSomething () Làm thế nào chúng ta có thể chế nhạo CallHandler ở đây?
Balaji Boggaram Ramanarayan

3

Tôi sử dụng HTTPClient của Apache (http://hc.apache.org/) để gọi Dịch vụ khôi phục. Thư viện HTTP Client cho phép bạn dễ dàng thực hiện lấy, đăng hoặc bất kỳ thao tác nào khác mà bạn cần. Nếu dịch vụ của bạn sử dụng JAXB cho liên kết xml, bạn có thể tạo một văn bản JAXBContext để tuần tự hóa và giải mã hóa các đầu vào và đầu ra từ yêu cầu HTTP.


3

Hãy xem trình tạo ứng dụng khách nghỉ ngơi của Alchemy . Điều này có thể tạo ra một triển khai proxy cho lớp dịch vụ web JAX-RS của bạn bằng cách sử dụng ứng dụng khách jersey đằng sau cảnh. Một cách hiệu quả, bạn sẽ gọi cho bạn các phương thức webservice như các phương thức java đơn giản từ các bài kiểm tra đơn vị của bạn. Xử lý xác thực http.

Không có việc tạo mã liên quan nếu bạn chỉ cần chạy các bài kiểm tra sao cho thuận tiện.

Tuyên bố từ chối trách nhiệm: Tôi là tác giả của thư viện này.


2

Giữ nó đơn giản. Hãy xem https://github.com/valid4j/http-matchers có thể được nhập từ Maven Central.

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

Ví dụ sử dụng:

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

1

Một điều quan trọng cần làm là kiểm tra độc lập logic kinh doanh của bạn

Tôi chắc chắn sẽ không cho rằng người đã viết mã JAX-RS và đang tìm cách kiểm tra đơn vị giao diện bằng cách nào đó, vì một số lý do kỳ lạ, không thể giải thích được, không biết đến khái niệm rằng anh ta hoặc cô ta có thể đơn vị kiểm tra các phần khác của chương trình, bao gồm các lớp logic nghiệp vụ. Hầu như không hữu ích khi nêu rõ điều hiển nhiên và quan điểm đã được đưa ra nhiều lần rằng các phản hồi cũng cần được kiểm tra.

Cả Jersey và RESTEasy đều có các ứng dụng khách và trong trường hợp của RESTEasy, bạn có thể sử dụng các thông báo giống nhau (thậm chí tính cả giao diện chú thích và sử dụng ở phía máy khách và máy chủ trong các thử nghiệm của bạn).

REST không phải những gì dịch vụ này có thể làm cho bạn; REST những gì bạn có thể làm cho dịch vụ này.


Mọi người có thể muốn kiểm tra một số mối quan tâm xuyên suốt. Ví dụ: xác thực, xác thực, tiêu đề HTTP mong muốn, v.v. Vì vậy, mọi người có thể thích kiểm tra mã JAX-RS của họ hơn.
Fırat KÜÇÜK

Trong ứng dụng của mình, tôi sử dụng ModelMapper để "ánh xạ" từ các lớp "DTO" sang các lớp "đối tượng nghiệp vụ", được hiểu bởi các lớp "dịch vụ" bên dưới. Đây là một ví dụ về một cái gì đó sẽ tốt để kiểm tra độc lập.
jkerak

Và đôi khi applet REST có độ phức tạp nhỏ đến mức các mocks sẽ lớn hơn lớp ứng dụng, như trong trường hợp hiện tại của tôi. :)
tekHedd

1

Như tôi hiểu, mục đích chính của trình xác thực vấn đề này là tách lớp JAX RS khỏi lớp kinh doanh. Và đơn vị chỉ kiểm tra cái đầu tiên. Hai vấn đề cơ bản ở đây chúng ta phải giải quyết:

  1. Chạy thử nghiệm một số máy chủ web / ứng dụng, đặt các thành phần JAX RS vào đó. Và chỉ họ.
  2. Mô phỏng các dịch vụ nghiệp vụ bên trong các thành phần JAX RS / lớp REST.

Cái đầu tiên được giải quyết bằng Arquillian. Điều thứ hai được mô tả hoàn hảo trong chữ arquillican và giả lập

Đây là một ví dụ về mã, nó có thể khác nếu bạn sử dụng một máy chủ ứng dụng khác, nhưng tôi hy vọng bạn sẽ có được ý tưởng cơ bản và những lợi thế.

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

Một số lưu ý:

  1. Cấu hình JAX RS không có web.xml được sử dụng ở đây.
  2. JAX RS Client được sử dụng ở đây (không có RESTEasy / Jersey, chúng tiết lộ API tiện lợi hơn)
  3. Khi thử nghiệm bắt đầu, người chạy của Arquillian bắt đầu hoạt động. Đây bạn có thể tìm thấy cách cấu hình các bài kiểm tra cho Arquillian với máy chủ ứng dụng cần thiết.
  4. Tùy thuộc vào máy chủ ứng dụng đã chọn, url trong thử nghiệm sẽ khác một chút. Cổng khác có thể được sử dụng. 8181 được sử dụng bởi Glassfish Embedded trong ví dụ của tôi.

Hy vọng, nó sẽ giúp ích.


loại thứ này có được hỗ trợ bởi khung kiểm tra jersey được xây dựng sẵn không? Tôi chỉ do dự để thêm "một khuôn khổ khác" và tất cả các lọ của nó vào dự án của tôi nếu tôi đã có sẵn thứ gì đó với Jersey.
jkerak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.