2017-02-10 70 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>