Without a UI, I know Acceptance Test Driven Development can still be performed against APIs etc (sort of headless vertical slice development and testing if you will) but where do we draw the line for the boundaries of things we are testing (I know, I know...it depends!)

Should we employ End-To-End testing or Component style testing? Or both ( and if the latter how do we deal with stuff coming out of test doubles)

Given a REST API, which creates commands, to be consumed asynchronously, and a messaging endpoint performing some action based on a command, which all reside in the same Microservice. To my mind, the boundaries are at the input into the REST api and the output of the messaging endpoint.

From a Microservice perspective, I can push in a request and get a message out of the back (mocking interactions with nearest neighbours) to get me to an end state in an End to End style test, and have done so. The drawback with this though is we start to create an hour glass instead of a testing triangle, If I am to ATDD all features like this. Which is a fair criticism

A bit of a debate has arisen about not exercising expensive HTTP calls, and messaging or Databases (which is all fair enough), more an End to End style of testing (favoured in GOOS for example) but rather using Component style testing but then this would omit the messaging aspect unless a test double for the messaging was pretty clever.)

Has anyone got any experience of any approach(es) to take, or considerations.


In my experience, you can achieve a good balance with the following ATDD approach for each use case you are test driving:

  1. Write your first test by interacting with the over-the-wire API of the microservice (e.g. REST API, JMS queue). This test will give you confidence that the "happy path" is working end to end.
  2. Use service virtualization to provide over-the-wire test doubles for that test. You can do some advanced stuff here such as capturing messages between your microservice and the test double and rendering the output (here is an example of such an approach)
  3. If there are any edge cases to test, write unit tests for them but still use the given-when-then style. Remember, a "unit" does not necessarily mean "one class". If you are writing code following something like a clean architecture you should be able to write a test as if it were end to end but providing in memory test doubles for all the pieces that would usually be over-the-wire.
  4. If you are rendering your acceptance tests, provide a link between the test that is over-the-wire and the unit level test so that from a documentation perspective it is easy to see both how the system behaves end to end and what all the unit level edge cases are for that use case.

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.