7

I've developed an SDK (link) for a RESTful API in PHP, and my automated tests (example) are actually live calls against the API, which is bad for multiple reasons, mainly:

  • it takes a long time (about 3 hours) for the tests to complete
  • it's impossible to do concurrent tests because they'll interfere with each other

I want to stop making live API calls.

I have an idea:

  • short circuit the request before it's fired
  • assert that the request URL is correct, in a way that, for example, if I pass a value John to the first_name param, I'd expect the request URI to contain first_name=John. Also, I have to be wary about optional params.

However, I don't think this is a full replacement because I lose the robustness of the response.

How do I know that the request is, in fact, valid without making a live call and checking the response code or JSON response?

Right now the library is using a random HTTP lib, but in the next major release which I'm working on right now, I will switch to Guzzle, which does support testing and short circuiting the request.

Finally, you can see an example of the API response here: https://reference.assemblypayments.com/#create-item

The Onin
  • 179
  • 4
  • 1
    `How do I know that the request is, in fact, valid without making a live call and checking the response code or JSON response?` -- You can't. However, if your software components are sufficiently decoupled, you can test each component independently. – Robert Harvey Sep 16 '17 at 15:21

3 Answers3

2

Identify what you're really wanting to test. Business rules are always paramount for me. I don't let business rule logic even know about the world around it. That means your business rules should only know about your robust response in the form of the most convenient data structure.

So long as that's all they expect you can test them with the most expedient way to create an example of that convenient data structure.

That may require code that converts the data structure to the convenient form. That you test with examples of both forms.

All that should be left to test is the access of the API. Here you can neglect the testing so long as access is simple. However, you can mock this with a local server that replicates the API if doing so actually does speed up the test.

If it doesn't at least you've separated what needs to be tested so you can work free of repeatedly running slow tests.

candied_orange
  • 102,279
  • 24
  • 197
  • 315
1

You want to test an a network call to a external resource you have no control over, right? I would suggest you put that access behind a interface or abstract resource that you control. Then you test your SDK against a mock version of the api that conforms to your SDK and returns the expected value.

Then when you write the implementation that covers the actual api you just need to make sure the api doesn't leak outside of that implementation. Later on, if the api changes or you want to replace it with something else, you can keep the interface intact and simply change the implementation, and your tests are still valid 'cause you control the interface.

As a bonus, if you want to add some tests that make sure the api is being called correctly just test the the implementation that you did covering the api without touching the SDK.

This is something called Clean Architecture / Ports and adapters and is meant to make the code easily testable.

Some reading material.

http://alistair.cockburn.us/Hexagonal+architecture https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

cllamach
  • 313
  • 2
  • 9
0

I suggest to focus on what you need to test: your SDK. In order to test it you need to replace actual calls to REST API with mocks. Those mock should be configured to simulate responses for different requests. For example when an HTTP GET request is sent with /users/12345 it will return JSON or XML that the real server would return.

Using that mock server you should be able to simulate different scenarios. For example, get user that does not exist should return Not Found, adding a user with the same username should return Conflict etc.