That's where we somewhat disagree on "invest heavily".
I believe you can test well enough by focusing on the semantic value an external service is providing (eg. S3 as a special purpose object or file storage with only a few operations, not a generic object storage; SQS could be a very simple event framework for most use cases), implementing only the very narrow use cases you need covered, and having a test which confirms that the simulated, local-only version behaves exactly the same as the one backed by the real service.
And really, with a well structured codebase, this should really not be very expensive.
The complexity really comes in with configurability, but as most components will really only depend on a few other (or your architecture is not well encapsulated), it shouldn't be too hard to run any individual one fully locally.
I am not saying this is "easy", but once you wrap your head around this approach, it's surprisingly simple and cheap: it provides just enough tests to cover everything, without covering many things with multiple tests (which also slows down development in the mid- and long-term).
In short, I have yet to see a software architecture that's inherently testable at all levels without it simply being a good architecture.
I believe you can test well enough by focusing on the semantic value an external service is providing (eg. S3 as a special purpose object or file storage with only a few operations, not a generic object storage; SQS could be a very simple event framework for most use cases), implementing only the very narrow use cases you need covered, and having a test which confirms that the simulated, local-only version behaves exactly the same as the one backed by the real service.
And really, with a well structured codebase, this should really not be very expensive.
The complexity really comes in with configurability, but as most components will really only depend on a few other (or your architecture is not well encapsulated), it shouldn't be too hard to run any individual one fully locally.
I am not saying this is "easy", but once you wrap your head around this approach, it's surprisingly simple and cheap: it provides just enough tests to cover everything, without covering many things with multiple tests (which also slows down development in the mid- and long-term).
In short, I have yet to see a software architecture that's inherently testable at all levels without it simply being a good architecture.