2017-02-10 69 views
2

我目前處於虧損狀態,單元測試了一個調用其中的REST服務的方法,用於向此服務發送狀態消息。休息調用的單元測試

我有這樣的方法:

public void informService(String state, BusinessObject bus) { 

    Client client = null; 
    Response response = null; 
    try { 

    client = new ResteasyClientBuilder() 
          .establishConnectionTimeout(10L, TimeUnit.MINUTES) 
          .socketTimeout(10L, TimeUnit.MINUTES) 
          .build(); 

     WebTarget target = client.target("my.url"); 

     MyDTO dto = new MyDTO(); 
     dto.state = state; 

     response = target.request("application/json").put(Entity.json(dto)); 

     boolean ok = handleReturnCode(response.getStatus(), bus.getId()); 

     if (!ok) { 
     throw new RuntimeException("Invalid status" + response.getStatus()); 
     } 

     return ok; 

    } catch (Exception e) { 
    } finally { 
    try { 
     if (response != null) { 
     response.close(); 
     } 
     if (client != null) 
     client.close(); 
    } catch (Exception e) { 
    } 
} 

所以該方法有哪個在方法中評估了REST服務的調用。我怎樣才能測試這種行爲?

+0

這真是醜陋的代碼我必須說。要測試這個,你可能想看看PowerMock,它可以幫助你 –

+0

該方法不遵循SOLID原則。將代碼拆分爲resposabilities。不要在方法中構建客戶端,將其作爲參數接收或使用工廠,這樣您就可以嘲笑它並僅測試內部邏輯。單元測試是關於測試方法/類邏輯,而不是與其他類的集成。 –

回答

1

當針對網絡服務的UnitTesting始終將實際網絡呼叫轉移到另一個Class並將其隱藏在Interface後面時。

然後,您可以爲該接口創建一個假對象。
在你測試你,然後注入假的服務,而不是真正的。

//Interface for your service 
public interface MyService{ 
    void sendJson(JsonObject json, Callback callback); 

    interface Callback{ 
     void onResult(int resultCode); 
    } 
} 

//Class you want to test 
public void MyClass{ 
    private MyService myService; 

    public MyClass(MyService myService){ 
     this.myService = myService; 
    } 

    public void informService(String state, BusinessObject bus) { 
     //Do the network call with your service and handle the response 
    } 

} 

現在,在您的測試,你可以創建一個FakeService延伸MyService並返回要測試的任何響應代碼。
當然你也可以使用像Mockito這樣的模擬框架來創建你的假貨,而不是你自己寫的。

+0

我喜歡這種方法,但我a)不能更改現有的代碼太多,b)我認爲這更像是一種集成測試。 –

+0

@SarahM不會改變你提出的問題是關於單元測試而不是集成測試的事實,這兩種類型的測試之間存在着差異。它違反網站規則發佈的答案不回答問題。 – Gimby

+0

對不起,我含糊不清。我想說的是,當我要求更多的單元測試時,提出的答案更多地進入了集成測試的方向。 –

0

我說一下功率模擬,所以我給你寫我寫什麼:

比方說,這是你的方法:

public boolean informService(String state) { 

     Client client = null; 
     client = new ClientBuilder().build(true); 

     boolean ok = client.getOK(); 

     if (!ok) { 
      throw new RuntimeException("Invalid status"); 
     } 

     return ok; 

} 

這是很容易版本的方法,但是我們仍然創造新的Builder在這裏,類被命名爲TestRest。爲了測試這顯然不好寫一段代碼,我們需要使用PowerMock:

@RunWith(PowerMockRunner.class) //clear 
@PrepareForTest(TestRest.class) //clear 
public class TestRestTest { 

    @Test 
    public void shouldReturnOKWhenOK() throws Exception{ 

     ClientBuilder builder = PowerMock.createMock(ClientBuilder.class); //prepare ClientBuilder mock to inject while test 

     TestRest tested = new TestRest(); //tested class, of course 

     PowerMock.expectNew(ClientBuilder.class).andReturn(builder); //What we expect when certain class will be instantiated using new, like in our example Builder 

     EasyMock.expect(builder.build(true)).andReturn(new Client(true)); //What we want to obtain, of course you will return some mocked object i think, especially that this is Unit test and you will want to test logic of method, not other classes 

     PowerMock.replay(builder, ClientBuilder.class); // change to replay mode to get configured expectation 

     assertTrue(tested.informService("state")); //clear 

     PowerMock.verify(builder, ClientBuilder.class); 
    } 

} 

而且在這裏你有Maven依賴:

<dependency> 
     <groupId>org.powermock</groupId> 
     <artifactId>powermock-easymock-release-full</artifactId> 
     <version>1.6.4</version> 
    </dependency> 
    <dependency> 
     <groupId>org.easymock</groupId> 
     <artifactId>easymock</artifactId> 
     <version>3.4</version> 
    </dependency> 
    <dependency> 
     <groupId>org.mockito</groupId> 
     <artifactId>mockito-all</artifactId> 
     <version>1.10.8</version> 
    </dependency>