2012-06-12 38 views
25

Tôi đã viết mã gọi API ứng dụng khách của Jersey mà lần lượt gọi một dịch vụ web nằm ngoài tầm kiểm soát của tôi. Tôi không muốn thử nghiệm đơn vị của mình gọi dịch vụ web thực tế.Làm cách nào để mã đơn vị thử nghiệm gọi API ứng dụng khách của Jersey?

phương pháp tốt nhất để viết một bài kiểm tra đơn vị cho mã mà các cuộc gọi của khách hàng API Jersey là gì? Tôi có nên sử dụng API máy chủ Jersey để viết dịch vụ web JAX-RS và sau đó sử dụng Khung kiểm tra Jersey cho thử nghiệm đơn vị không? Hoặc tôi có nên thử các cuộc gọi dịch vụ web Jersey không? Tôi có quyền truy cập vào JMock. Hay tôi nên thử cách tiếp cận khác?

Trong nghiên cứu của tôi, tôi thấy this discussion mô tả tùy chọn khác nhau, nhưng tôi đã tìm thấy một giải pháp hoàn chỉnh. Có bất kỳ ví dụ mã nào có sẵn cho thấy cách tiếp cận JUnit được đề xuất không? Tôi không thể tìm thấy bất kỳ tài liệu nào trong tài liệu của Jersey.

Đây là mã nguồn có liên quan:

public String getResult(URI uri) throws Exception { 
    // error handling code removed for clarity 
    ClientConfig clientConfig = new DefaultClientConfig(); 
    Client client = Client.create(clientConfig); 
    WebResource service = client.resource(uri); 
    String result = service.accept(accept).get(String.class); 
    return result; 
} 

Dưới đây là ví dụ về mã kiểm tra Tôi muốn vượt qua. Tôi muốn kiểm tra (1) truyền vào một URI hợp lệ và nhận được một chuỗi hợp lệ trở lại và (2) chuyển vào một URI không hợp lệ (vì bất kỳ lý do gì - không thể truy cập hoặc không được phép) và nhận lại một ngoại lệ.

@Test 
public void testGetResult_ValidUri() throws Exception { 
    String xml = retriever.getResult(VALID_URI); 
    Assert.assertFalse(StringUtils.isBlank(xml)); 
} 

@Test(expected = IllegalArgumentException.class) 
public void testGetResult_InvalidUri() throws Exception { 
    retriever.getResult(INVALID_URI); 
} 

Mọi thứ ở trên là mô tả đơn giản về mã của tôi. Trong thực tế, có một lớp trên đầu trang chấp nhận hai URI, đầu tiên cố gắng gọi URI đầu tiên và nếu URI đó thất bại thì nó sẽ cố gắng gọi URI thứ hai. Tôi muốn có các bài kiểm tra đơn vị bao gồm (1) URI đầu tiên thành công, (2) URI đầu tiên không thành công và URI thứ hai thành công, và (3) cả hai URI đều thất bại. Mã này là đủ phức tạp mà tôi muốn thử nghiệm các kịch bản khác nhau này bằng cách sử dụng JUnit, nhưng để thực hiện điều này, tôi cần phải chạy các dịch vụ web thực sự tồn tại hoặc giả lập các cuộc gọi API khách hàng Jersey.

+0

gì chính xác làm bạn muốn kiểm tra trong phương pháp này? Các tiêu chuẩn là gì, bài kiểm tra đó được thông qua? – dbf

+0

Vâng, nếu bạn muốn làm bài kiểm tra đơn vị thì bạn phải có các dịch vụ chức năng thích hợp. – iDroid

+0

@dbf Tôi đã cập nhật câu hỏi mà tôi muốn kiểm tra (1) chuyển vào một URI hợp lệ và nhận lại một chuỗi hợp lệ và (2) chuyển vào một URI không hợp lệ (vì bất kỳ lý do gì - không thể truy cập hoặc không được phép) và nhận một ngoại lệ trở lại. – BennyMcBenBen

Trả lời

12

Hãy thử sử dụng Mockito hoặc Easymock để thực hiện các cuộc gọi dịch vụ nhại. Bạn chỉ cần giả lập những phương pháp này thực sự được sử dụng - không cần phải giả lập mọi phương thức. Bạn có thể tạo đối tượng giả cho lớp WebResource, sau đó giả định gọi phương thức chấp nhận.

Trong @ BeforeClass/@ Trước khi thử nghiệm JUnit phương pháp ghi một cái gì đó tương tự (ví dụ Mockito)

WebResource res = mock(WebResource.class); 
when(res.accept(something)).thenReturn(thatWhatYouWant); 

Sau đó, trong các thử nghiệm của bạn, bạn có thể sử dụng đối tượng res như thể nó là đối tượng thực tế và gọi phương thức giả trên đó. Thay vì trả về giá trị bạn cũng có thể ném ngoại lệ. Mockito khá thú vị.

+1

Đây là câu trả lời đúng. Làm cho toàn bộ dịch vụ web đang nỗ lực thử nghiệm mã Jersey khi tôi đã biết rằng nó hoạt động. Tôi muốn kiểm tra mã của tôi. Tôi đã kết thúc việc tái cấu trúc các cuộc gọi đến mã Jersey sang một lớp khác, thêm một setter, và chế nhạo lớp mới. Điều này làm việc hoàn hảo và cho phép tôi kiểm tra các kịch bản khác nhau mà tôi thực sự muốn thử nghiệm. Nhóm của tôi đang sử dụng JMock nên tôi đã kết thúc bằng cách sử dụng điều đó, nhưng mọi khuôn khổ mocking sẽ làm. – BennyMcBenBen

+0

Tôi hơi bối rối vì trang web Mockito tuyên bố "Đừng chế nhạo loại bạn không sở hữu!" Chúng ta vẽ một đường thẳng tới những gì chúng ta có thể so sánh với không. Có cách nào tốt hơn? –

0

Chỉ cần thực hiện một dịch vụ việc tương tự và trong thiết lập thử nghiệm đơn vị của bạn bắt đầu dịch vụ sử dụng HttpServerFactory.

11

Thông thường những gì bạn thực sự sau là "cách tôi sử dụng DSL của khách hàng Jersey tạo yêu cầu tới URL chính xác với thông số tải trọng và URL chính xác". Thử nghiệm điều này với Mockito thực sự tiết lộ và mã thiết lập thường sẽ kết thúc bằng một cái gì đó như thế này:

when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication); 
    when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication); 
    when(testAuthentication.request(
      MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder); 
    when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse); 
    when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse()); 

Và điều này về cơ bản chỉ dành cho một yêu cầu REST đơn. Đó là quá chi tiết, và thay vì thử nghiệm kết quả hy vọng bạn chỉ cần sao chép các bước bạn nghĩ là chính xác trong việc sử dụng ứng dụng khách của DSL.

Thay vì ở trên, tôi sẽ hướng đến chế nhạo một dịch vụ đơn giản.Đối với điều này tôi đã sử dụng WireMock bắt đầu một máy chủ Jetty và nơi tôi có thể phân phát những thứ như "mong đợi một yêu cầu đến URL này, phản hồi với thông báo này và xác minh rằng tải trọng là" này.

Tôi biết điều này đang được thử nghiệm tích hợp và chậm hơn một chút so với chỉ sử dụng Mockito nhưng tôi đánh giá thử nghiệm kết quả thực và tôi đánh giá khả năng đọc của cách kiểm tra nhiều hơn trong trường hợp này.

cài đặt cho một WireMock dựa Jersey kiểm tra khách hàng trông giống như sau:

@Test 
public void exactUrlOnly() { 
    stubFor(get(urlEqualTo("/some/thing")) 
      .willReturn(aResponse() 
       .withHeader("Content-Type", "text/plain") 
       .withBody("Hello world!"))); 

    assertThat(testClient.get("/some/thing").statusCode(), is(200)); 
    assertThat(testClient.get("/some/thing/else").statusCode(), is(404)); 
} 
+0

+1 cho WireMock - công cụ tuyệt vời. Trong trường hợp của tôi, Mockito không thể giả mạo WebResource.Builder (cuối cùng), được giải quyết bằng WireMock – denismo

Các vấn đề liên quan