Skip to content

Commit ca7ac35

Browse files
committed
recap and prior art
1 parent 1aa15fd commit ca7ac35

1 file changed

Lines changed: 65 additions & 5 deletions

File tree

_posts/2020-01-25-testing_external_api_calls.md

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,16 @@ have one of these each time we introduce a new option.
277277

278278
## SUGGESTION: Build an Adapter (a wrapper for the external API)
279279

280+
We really want to disentangle our business logic from our API integration.
281+
Building an abstraction, a wrapper around the API that just exposes nice,
282+
readable methods for us to call in our code.
283+
284+
> We call it an "adapter" in [ports & adapters](https://github.com/cosmicpython/book/blob/master/chapter_02_repository.asciidoc#what_is_a_port_and_what_is_an_adapter) sense,
285+
> but you don't have to go full-on hexagonal architecture to use
286+
> this pattern.
287+
288+
280289

281-
You'll probably tend towards
282290
```python
283291
class RealCargoAPI:
284292
API_URL = 'https://example.org'
@@ -562,6 +570,14 @@ or they might be a useful backup option if proper integration tests aren't
562570
possible. In a similar way, you probably want ways of _selectively_ running
563571
your contract tests against your third party.
564572

573+
> you can also run your contract tests against your fake api.
574+
575+
When you run your contract tests against your own fake api as well as
576+
against the real thing, you're confirming the quality of your fake.
577+
Some people call this [verified fakes](https://pythonspeed.com/articles/verified-fakes/)
578+
(see also ["stop mocking and start testing"](https://nedbatchelder.com/blog/201206/tldw_stop_mocking_start_testing.html).)
579+
[](https://nedbatchelder.com/blog/201206/tldw_stop_mocking_start_testing.html)
580+
565581

566582
## OPTION: DI
567583

@@ -695,12 +711,56 @@ The design pressure is the killer argument in our opinion. Because hand-rolling
695711
a fake _is_ more effort, it forces us to think about the API of our adapter,
696712
and it gives us an incentive to keep it simple.
697713

698-
(callback to initial decision to build a wrapper. the fake helps do it right)
714+
If you think back to our initial decision to build a wrapper, in our toy example
715+
it was quite easy to decide what the adapter should look like, we just needed
716+
one public method called `sync()`. In real life it's sometimes harder to figure
717+
out what belongs in an adapter, and what stays in business logic. By forcing
718+
ourselves to build a fake, we get to really see the shape of the thing that
719+
we're abstracting out.
720+
721+
* See this excerpt from our book in which we talk about
722+
[heuristics for abstracting out dependencies](http://www.obeythetestinggoat.com/new-book-excerpt-abstractions.html).
723+
724+
725+
> For bonus points, you can even share code between the fake class you use
726+
> for your unit tests, and the fake you use for your integration tests.
727+
728+
729+
730+
731+
## Recap
732+
733+
* As soon as your integration with an external API gets beyond the trivial,
734+
mocking and patching starts to be quite painful
735+
736+
* Consider abstracting out a wrapper around your API
737+
738+
* Use integration tests to test your adapter, and unit tests for your
739+
business logic (and to check that you call your adapter correctly)
740+
741+
* Consider writing your own fakes for your unit tests. They will
742+
help you find a good abstraction.
743+
744+
* If you want a way for devs or CI to run tests without depending
745+
on the external API, consider also writing a fully-functional fake of the
746+
third-party API (an actual web server).
747+
748+
* For bonus points, the two fakes can share code.
749+
750+
* Selectively running integration tests against both the fake and the real API
751+
can validate that both continue to work over time.
752+
753+
* You could also consider adding more targeted "contract tests" for this purpose.
754+
699755

700-
* link to [example code](https://github.com/cosmicpython/code/tree/blogpost-testing-api)
756+
> If you'd like to play around with the code from this blog post, you can
757+
> [check it out here](https://github.com/cosmicpython/code/tree/blogpost-testing-api)
701758

702759

703-
# TODOS:
760+
## Prior art
704761

705-
* link to Brandon [Hoist your I/O](https://www.youtube.com/watch?v=PBQN62oUnN8) video?
762+
* [Mock Hell](https://www.youtube.com/watch?v=CdKaZ7boiZ4) by Ed Jung
763+
* [stop mocking and start testing](https://nedbatchelder.com/blog/201206/tldw_stop_mocking_start_testing.html) by Augie Fackler Nathaniel Manista (and summarised by Ned Batchelder)
764+
* [verified fakes](https://pythonspeed.com/articles/verified-fakes/) by Itamar Turner-Trauring
765+
* [Hoist your I/O](https://www.youtube.com/watch?v=PBQN62oUnN8) by Brandon Rhodes
706766

0 commit comments

Comments
 (0)