Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start with TDD for a RESTful api

Tags:

java

tdd

I'm trying to practice TDD and have an exercise to do. There is an existing service deployed somewhere in internet having public RESTful api. Each request to this api requires some data preparation like valid request string construction, some encryption, some body message formatting etc. I'd like to write generic client for this service using TDD.

I know it is not as simple as e.g. StringCalculator kata, and requires a bit different approach.

I don't know how to start with that. I'd like to test it without using real service, so there is kind of fake impl required. Is it better to write some fake implementation, deploy it on localhost and call it from my tests? Or maybe mock a class responsible for sending http request?

I'd like my client usage to be as below:

public class ServiceClientTest {
   @Test
   public void testSendStoreRequest() {
        ServiceClient client = new ServiceClient("app_key", "private_key")
        ClientResponse response = client.sendStoreRequest(StorageType.NORMAL,     "string_to_store");
       assertEquals("200", response.getStatus());
   } 
}

Can you point me any direction on how to start with this? Should I start bottom-up and writing all the components (for request string creation, for encryption etc) and then use them all in ServiceClient, or should I start from ServiceClient test and implementation with top-down and mocking?

like image 804
grafthez Avatar asked Oct 17 '11 08:10

grafthez


1 Answers

First of all, don't mock external APIs. Why? Cos you don't own them.

The ideal solution for your problem seems to be what you started describing. You should create an interface in your project that you own, that will represent the external service.

public interface CalculatorService {
    int add(int a, int b);
}

This will be your border for testing. All your UNIT and ACCEPTANCE tests should run against a mock or stub of CalculatorService. They will be fast. You can do that since it is you who defines that contract (what that interface actually means).

Later, you will have an implementation that goes to that remote HTTP rest service:

class RemoteRestCalculator implements CalculatorService {
    public int add(int a, int b) {
        // call the remote service in here
    }
}

You need to test this contract (border). So you will write integration tests just for the RemoteRestCalculator. You can also have couple of end-to-end tests that run application with the RemoteRestCalculator to test the wiring, etc.

Now, to answer you question, how to test that RemoteRestCalculator?

  1. Ideally you would deploy an instance of the real http rest service in your testing environment, point it to a testing database, etc. So you talk to the guys that own that service, they provide you with the *.war file and you deploy it locally with test database etc. Sometimes they do it for you, a "sandbox" deployment of that service.. Then you write test for RemoteRestCalculator that run against that instance.
  2. Another solution is similar to what you mentioned. Create a "http rest service simulator". Then deploy it locally. The trick is that you will have to replicate the real service behaviour for all functionalities you use in that simulator. So, the simulator "add" method will have to behave the same as the real one. There is a lot of strong pros and cons to this solution. Then you write test for RemoteRestCalculator that run against that simulator.
  3. There is a mid-way solution that is used quiet commonly in the industry. You just run all your tests against the local test deployment of the real service (or sometimes the simulator). The test suite can be very slow unfortunately in this case when you have lots of tests. Not recommended. Further reading about making builds go faster.
  4. There is one more solution used commonly which is not recommended in most cases. You create a "http rest stub class", that is used kind of like mockito mock but it always talks via http. So usually it would start a http server and you would prime it before use use it. It has a lot more disadvantages than advantages. The biggest disadvantage is that the behaviour of the service (external dependency) is scattered across many tests in your application. Not recommended.
like image 112
Wojtek B. Avatar answered Oct 20 '22 01:10

Wojtek B.