BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Restfuse 1.0.0 - A Library For Easy REST/HTTP Integration Tests

Restfuse 1.0.0 - A Library For Easy REST/HTTP Integration Tests

Leia em Português

This item in japanese

EclipseSource has released the first stable version for an open source JUnit extension that automates testing of REST/HTTP services. Restfuse is a set of JUnit annotations that, along with the respective HttpJUnitRunner, offer assertions against the response of an HTTP call. Both synchronous and asynchronous remote calls are supported.

Restfuse is already in Maven Central so using it requires no special repository:

<dependency>
    <groupId>com.restfuse</groupId>
    <artifactId>com.eclipsesource.restfuse</artifactId>
    <version>1.0.0</version>
</dependency>

Using the library for synchronous calls is straightforward:

@RunWith( HttpJUnitRunner.class )
public class RestFuseTest {

  @Rule
  public Destination destination = new Destination( "http://example.com" ); 

  @Context
  private Response response; // will be injected after every request

  @HttpTest( method = Method.GET, path = "/reloadLocalConfiguration" )
  public void checkRestfuseOnlineStatus() {
    assertOk( response );
    String answerBody = response.getBody(String.class);
    assertEquals("Expected correct response","done",answerBody);
  }  
}

The test above calls an HTTP endpoint synchronously and then checks for a text-based response (text/plain) with the "done" string. Notice that the first assertOk is a Restfuse assert that checks for the HTTP 200 OK status call while the second assertEquals is the usual string equality assert offered by JUnit. While this endpoint is assumed to return plain text, one could easily parse JSON/XML or something else and perform asserts in a structured manner.

Restfuse also supports asynchronous calls. The canonical example is a long running operation (e.g. progress on a file upload). The client continuously polls the server endpoint in order to gather constant feedback on the actual status. Let's assume a server endpoint that returns a number between 0 and 100 that denotes progress on some operation:

@RunWith( HttpJUnitRunner.class )
public class PollTest1 {

  @Rule
  public Destination destination = new Destination( "http://example.com" ); 

  @Context
  private Response response;
  
  @Context
  private PollState pollState;

  @HttpTest( method = Method.GET, path = "/progressStatus" )
  @Poll( times = 5, interval = 500 )
  public void testAsynchronousService() {
    if(pollState.getTimes() == 5)
    {
	    String answerBody = response.getBody(String.class);
	    assertEquals("Expected last response","100",answerBody);
    }
  }  
}

The test above calls the same endpoint 5 times (with a specified interval) and only on the last call checks the actual HTTP response.

Another interesting feature of the PollState Interface is that it keeps track of all the previous responses at each point in time. This allows for asserts on the history of the calls:

@RunWith( HttpJUnitRunner.class )
public class PollTest2 {

  @Rule
  public Destination destination = new Destination( "http://example.com" ); 

  @Context
  private Response response;
  
  @Context
  private PollState pollState;

  @HttpTest( method = Method.GET, path = "/progressStatus" )
  @Poll( times = 5, interval = 500 )
  public void testAsynchronousService() {
	int currentRun = pollState.getTimes();
	if(currentRun > 1)
	{
		String previousProgress = pollState.getResponse(currentRun - 1).getBody(String.class);
		String presentProgress = response.getBody(String.class);
		assertTrue("Expected some progress",Integer.parseInt(presentProgress) > Integer.parseInt(presentProgress)); //Just for illustration purposes
	}
    }
  }  
}

The test above checks that each response is a higher number than the previous one.

One of the most surprising dependencies of Restfuse is the Jetty HTTP server. The reason for this is that Restfuse also supports asynchronous services that follow the Web Hooks guidelines. Instead of polling multiple times the server, a client endpoint performs a call only once and then waits for a response initiated by the server in a completely different connection. Here is the Restfuse example:

@RunWith( HttpJUnitRunner.class )
public class RestfuseCalbackTest {
 
  @Rule
  public Destination destination = new Destination( "http://example.com" );
    
  @Context
  private Response response;
   
  private class TestCallbackResource extends DefaultCallbackResource {

    @Override
    public Response post( Request request ) {
      assertTrue("Expected a quote response", request.getBody(String.class).startsWith("quote:") );
      return super.post( request );
    }
  }
   
  @HttpTest( method = Method.GET, path = "/requestQuote" )
  @Callback( port = 9090, path = "/asynchron", resource = TestCallbackResource.class, timeout = 10000 )
  public void testMethod() {
    assertAccepted( response );
  }
}

The example above will connect to requestQuote once and then listen to port 9090 of the client. Within 10 seconds it will expect a connection that is text-based and starts with "quote:".

For more extensive information, visit the Wiki, and Javadocs. The source code is hosted on GitHub.

Rate this Article

Adoption
Style

BT