如何TDD for Restful客户端代码示例

时间:2012-05-08 13:58:09

标签: java rest tdd resteasy rest-client

之前我做了一些TDD,但它们只是简单明了。

但是,我将实现一个宁静的客户端并调用第三方的宁静API(Twitter或Jira)。

我使用Resteasy客户端框架来实现它。代码是:

public void invokePUT() {
     ClientRequest request =
                 new ClientRequest("http://example.com/customers");
     request.accept("application/xml");
     ClientResponse<Customer> response = request.put(Customer.class); 
     try {
          if (response.getStatus() != 201)
               throw new RuntimeException("Failed!");
     } finally {
          response.releaseConnection(); 
     }}

如果我想为这个方法编写一个测试(应该在实现这个方法之前编写测试),我应该编写什么样的代码。

对于GET,我可以测试返回Entity等于我的预期实体,对于POST,我可以测试创建的实体的id不为null。

但PUT和DELETE怎么样?感谢。

3 个答案:

答案 0 :(得分:2)

尝试使用REST Assured测试框架。它是测试REST服务的绝佳工具。在他们的网站上,你会发现大量的例子如何使用它。只需将它与JUnit或TestNG一起使用来检查断言即可。

答案 1 :(得分:1)

如果put和delete按预期调用(带有预期的参数等),我会注入测试的模拟类。 easymock或类似的东西对此有好处 (与发布相同)

编辑: 如果你想测试其余的客户端,使用依赖注入来注入请求,然后使用easymock来模拟它(例如测试,如果正确调用delete):

@Test void myTest(){
 ClientRequest mock = EasyMock.createMock(ClientRequest.class);
 mock.delete(2); //test if resource with id=2 is deleted or something similar

 EasyMock.replay(mock);
 invokeDelete(mock);
 EasyMock.verify(mock);
}

答案 2 :(得分:1)

以下是我如何在短期内解决问题:

1)将请求提取到方法的参数中。 invokePUT()现在变为:

public void invokePUT(ClientRequest request) {
    request.accept("application/xml");
    ClientResponse<Customer> response = request.put(Customer.class); 
    try {
         if (response.getStatus() != 201)
              throw new RuntimeException("Failed!");
    } finally {
         response.releaseConnection(); 
    }
}

2)在测试中,使用简化版ClientRequest

@Test
public void sendsPayloadAsXml() {
    StubbedClientRequest request = new StubbedClientRequest(new StubbedResponse());
    restApi.invokePUT(request);
    assertEquals("application/xml", request.acceptHeader);
}

@Test
public void makesTheCallUsingPut() {
    StubbedClientRequest request = new StubbedClientRequest(new StubbedResponse());
    restApi.invokePUT(request);
    assertTrue(request.putWasCalled);
}

@Test
public void releasesTheConnectionWhenComplete() {
    StubbedResponse success = new StubbedResponse();
    StubbedClientRequest request = new StubbedClientRequest(success);
    restApi.invokePUT(request);
    assertTrue(success.connectionWasClosed);
}

@Test(expected = RuntimeException.class)
public void raisesAnExceptionWhenInvalidResponseReceived() {
    StubbedClientRequest request = new StubbedClientRequest(new StubbedResponse(400));
    restApi.invokePUT(request);
}

private static class StubbedClientRequest extends ClientRequest {
    public String acceptHeader = "";
    public boolean putWasCalled;
    public ClientResponse response

    public StubbedRequest(ClientResponse response) {
        this.response = response;
    }

    @Override
    public ClientResponse put(Class klass) {
        putWasCalled = true;
        return response;
    }

    @Override
    public void accept(String header) {
        acceptHeader += header;
    }

}

private static class StubbedResponse extends ClientResponse {
    public boolean connectionWasReleased;
    public int status = 201;

    public StubbedResponse(int status) {
        this.status = status;
    }

    public StubbedResponse() { }
}

这可能不是一个完美的设计(将ClientRequest交给班级并让RestEasy的东西暴露给外界)但这是一个开始。

希望有所帮助!

布兰登