Invert your dependencies: make the external service into a plugin to your application. Then, attach different implementations depending on whether you're running in a production environment or a development environment.
First, define an interface through which your application communicates with the third party service. With interface I mean anything from a bunch of functions in your code to a REST API, the important point is just that you can select an implementation of this interface at run time. For example, you could provide an environment variable that contains an URL that points to a microservice that provides the expected interface. Or, you could have an if/else at the beginning of your program that selects one of two classes.
Then, create two implementations of your interface:
The point is that instead of choosing the real or mock implementation throughout your code, that your main code remains agnostic to which implementation it is talking with. This is more testable, and also much less error-prone. The decision to use a particular implementation is made once, and preferably outside of the app. Instead, the choice should be made by the environment in which the app is being run.
Related concepts:
- Configuration and backing services in the 12-Factor App, a guide for developing SaaS style software.
- The idea to avoid dependencies from your business logic to external components is also part of the idea of the Onion Architecture: “Inner layers define interfaces. Outer layers implement interfaces”. This style of architecture has substantial overlap or is equivalent with hexagonal architecture (ports and adapters) and clean architecture.
- On a lower level, replacing repeated if/else with multiple classes is known as the replace conditional with polymorphism refactoring.