I've done this as follows: create a service layer that makes the API calls to external services. I built mine on Spring's RestTemplate but you could use whatever library to make calls. So it'll have methods like get() or post().
Then I use Postman to perform some requests against the external API and save the responses in files and add these files to my project.
Finally, in my tests, I mock out the calls to my little API service layer so that instead of going to the external API, it reads from the test files I saved previously. This runs the code under test with known payloads that came from the external API, but without requiring a connection to it during the test, and which won't change until I update the responses in the files myself.
I use EasyMock but any mocking library will work. Here's an example of what a test looks like.
@Test
public void test_addPhoneToExternalService() {
// Mock my real API service.
ApiService mockApiService = EasyMock.createMock(ApiService.class);
// Construct my service under test using my mock instead of the real one.
ServiceUnderTest serviceUnderTest = new ServiceUnderTest(mockApiService);
// Expect the body of the POST request to look like this.
Map<String, Object> requestBody = new HashMap<String, Object>() {{
put("lists", 0);
put("phone", "800-555-1212");
put("firstName", "firstName");
put("lastName", "lastName");
}};
// Read the response that I manually saved as json.
JsonNode expectedResponse = Utils.readJson("response.json");
expect(mockApiService.post(anyObject(),
eq("https://rest.someservice.com/api/contacts"), eq(serialize(requestBody))))
.andReturn(expectedResponse);
EasyMock.replay(mockApiService);
// Call the code under test. It ingests the response
// provided by the API service, which is now mocked,
// and performs some operations, then returns a value
// based on what the response contained (for example,
// "{\"id\":42}").
long id = serviceUnderTest.addPhone("firstName", "lastName", "800-555-1212");
Assert.assertThat(id, is(42L));
EasyMock.verify(mockApiService);
}
Hope that helps!