38

This is something that's been troubling me for a while now. Is it actually worth unit-testing an API client?

Let's say you're creating a small class to abstract-away the calls to a petshop REST API. The petshop is a very simple API, and it has a basic set of methods:

  • listProducts()
  • getProductDetails(ProductID)
  • addProduct(...)
  • removeProduct(ProductID)

In testing this, we'd have to either create a mock service or mock the responses. But that seems overkill; I understand that we want to make sure that our methods don't stop working through typo/syntax errors, but since we're writing functions that call remote methods and then we're creating fake responses from those remote methods, it does seem like a waste of effort and that we're testing something that can't really fail. Worse, if the remote method changes our unit tests will pass while production use fails.

I'm pretty sure I'm missing something, or I've got the wrong end of the stick, or I'm not seeing the wood for the trees. Can someone set me on the right track?

  • 1
    If this weren't such a simple API with basic methods, would you feel different? Even a shed has to stand up to the snow. – JeffO Aug 8 '14 at 15:23
31

The job of a remote API client is to issue certain calls - no more, no less. Therefore, its test should verify that it issues those calls - no more, no less.

Sure, if the API provider changes the semantics of their responses, then your system will fail in production. But that isn't your client class's fault; it's something that can only be caught in integration tests. By relying on code not under your control you have given up the ability to verify correctness via internal testing - it was a trade-off, and this is the price.

That said, testing a class that consists only of delegations to another class may be low-priority, because there is comparatively little risk of complex errors. But that goes for any class that consists only of uniform one-liners, it has nothing to do with calling out into another vendor's code.

  • Mmm, not sure I agree. You can test that foo() gets called before bar(), but that doesn't mean calling foo() before bar() is the correct thing to do; a unit test like that would pass even if the code is wrong. And if that's all the client is doing, setting up the mocks that check if foo() gets called before bar() is relatively troublesome for something that can be verified with a cursory glance at the client code. – Doval Aug 8 '14 at 14:08
  • 1
    You can test that an add() methods adds two numbers correctly, but that doesn't mean that adding is the right thing to do at this point in the algorithm - the add() unit test would succeed even though your program is wrong. If it is the wrong thing, then your levenshteinDistance() method is to blame, not the add() method. This is exactly the same. The point of having code separated into methods is always that each method only has to care about getting one thing correct. – Kilian Foth Aug 8 '14 at 14:25
  • 3
    Now I see where we disagree! If you rely on an external pet shop, to me this means that your system ends at the HTTP boundary, therefore the issued REST calls are outputs and subject to testing. If you consider the pet shop part of this module, then yes, the pattern of issued calls is an implementation detail, and a unit test has no business prescribing anything about them. – Kilian Foth Aug 8 '14 at 14:32
  • 2
    "Therefore, its test should verify that it issues those calls" I think that's the perspective I was failing to see. Thanks! – Phillip B Oldham Aug 11 '14 at 9:39
  • 1
    So for example my unit test could check that, given certain parameters, the body of the request it is about execute is the correct one? – Maria Ines Parnisari Jun 16 '15 at 3:29
9

Short answer:

All methods should be unit-tested.

Long answer:

Yes. It is worth it.

These are some things unit tests on those API-calling methods should test:

  • That you are passing well-formed or correct parameters to the API calls.
  • That you are responding accordingly to certain types of data returned by the APIs (mocked or not), for example maybe when the API returns an empty string your method should return a default value (just an example)
  • That the caller methods behave correctly when API calls produces an error

Those are things the called method do that can be isolated my mocking the API service, and that by testing them well, assure you that errors are not originated by an error in the client code that calls the API.

  • You say "mocked or not"... so is it okay to test against the real API? Can I call it an integration test even though it looks like a Unit Test? Or is there another thing to call this? I'd love to test that my API wrapper does what it says it does, somehow... – Dan Rosenstark Apr 20 '17 at 14:02
  • 1
    @DanRosenstark I guess in the case the API service not being mocked, it's an integration test. – Tulains Córdova Apr 20 '17 at 19:03
  • Wouldnt you know in 5 seconds if you are getting data back properly when you make an actual call to the API? Since the API mocks are not real calls the only way they would fail is if they change the API...in that case your mock tests would pass but the real calls would fail. Seems pointless – MattE Jul 4 at 22:03
5

These would not be unit tests because you are testing the input and output of your system, more like limited integration tests.

Be very cautious when you say "it does seem like a waste of effort and that we're testing something that can't really fail" - it can fail, it will fail, it will probably fail in ways that you cannot anticipate, the failures will be worse if you don't have tests in place.

The mistake you are making here is to do with the invention of wheels: Making calls to remote services and APIs is a very common scenario so there are some pretty good tools to help you test that. Last time I was working on an application that connected to remote services I used SoapUI which could look at a service and either make mock calls to that service or behave as a local copy of the server that you can make test calls against and track through the requests and responses. It took minutes to set up and likewise was very quick to update if the remote interface changed. I haven't used it in a REST scenario, but even if it doesn't work well for that ( or perhaps someone is reading this answer in the future when better tools exist ) you should be able to find a tool that can mock up a service for you and when it comes time to deploy your code, you will be glad that you did.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.