I just figured out why callback style APIs are harder to test (and harder to deal with in general). It’s because they break one of the essential ingredients of a hexagonal architecture: the middle hexagon should be independent of the adapters. Here’s why…

In order to use a callback API, one or more of our application classes must implement the callback method(s), and must therefore conform to some abstraction defined by the API’s provider. So our classes must depend on the API. Which means that the API can’t be easily mocked or stubbed. We have to treat our callback objects as being part of the adapter for that API, and test the rest of the application by mocking or stubbing them.

In fact, now I’ve written it down it’s trivially obvious, and hardly worth saying.

As you were.


  1. Hi Kevin,

    I’m afraid I don’t follow your logic when you say, “So our classes must depend on the API. Which means that the API can’t be easily mocked or stubbed.”

    Sure, to make yourself available for callback in a static language you’d have to implement an interface of some sort, but I don’t see why that makes it hard to test. In fact, I’ve always found callback APIs easier to unit test, since you can pass a test implementation into the call-back API to test that, and you can just call the callback method on the implementee without the need to touch the callback API.

    I did notice as I was writing this, that I kept thinking of a callback interface with only a single method on it. I don’t like callback APIs where you have to implement multiple methods since it is a) more complex and b) leaves you to deal with the vagaries of call order dependency.

    Objective C and Cocoa make extensive use of callbacks, but there they even forgo the need to implement an interface. The Cocoa APIs will check if you implement a method with a certain signature and, if you do, they’ll call it. This makes me very nervous, but seems to work out extremely well.

  2. Hi Rob,
    Should have taken more time…
    I was thinking of cases in which there are lots of callback methods to implement, probably with an implied calling sequence. So the client (ie. callee) is effectively a plug-in to a Template Method over which one has little or no control. Yes, the callee’s methods can often be tested individually. And for best results I like to ensure that the callee depends on the rest of the app, and not the other way around.




Leave a Comment