|
| 1 | +--- |
| 2 | +title: Testing external API calls |
| 3 | +layout: post |
| 4 | +author: Harry |
| 5 | +categories: |
| 6 | + - testing |
| 7 | +tags: |
| 8 | + - tdd |
| 9 | + - fakes |
| 10 | + - mocks |
| 11 | + - adapters |
| 12 | +--- |
| 13 | + |
| 14 | +## Notes |
| 15 | + |
| 16 | +common question, how do i write tests for external api calls |
| 17 | + |
| 18 | + example tbc |
| 19 | + |
| 20 | +common solution. use mocks and mock.patch. fine, actually, if you |
| 21 | +have just one call to one endpoint |
| 22 | + |
| 23 | +pros: |
| 24 | +* no change to client code |
| 25 | +* low effort |
| 26 | +* everyone understands it |
| 27 | + |
| 28 | +cons: |
| 29 | +* tightly coupled |
| 30 | +* brittle. requests.get -> requests.Session().get will break it. |
| 31 | +* need to remember to `@mock.patch` every single test that might |
| 32 | + end up invoking that api |
| 33 | + |
| 34 | + |
| 35 | +- could mention vcr.py here. ingenious but i've found it confuses ppl. |
| 36 | + |
| 37 | +* and you still need an integration test or two, and maybe an E2E test. |
| 38 | + so you need a sandbox, or some way of faking it out irl |
| 39 | + |
| 40 | +link to ed "mocking pitfalls" video |
| 41 | + |
| 42 | + |
| 43 | +# step 1: DI |
| 44 | + |
| 45 | + example |
| 46 | + |
| 47 | +- this will fix your brittleness and "remember to mock.patch" problem |
| 48 | +- comes at the cost of a new "unnecessary" argument to your app code |
| 49 | +* some people like that tho. |
| 50 | + |
| 51 | + |
| 52 | +link to brandon "hoist your io" video |
| 53 | + |
| 54 | + |
| 55 | +# step 2a: build an adapter. or a wrapper. or whatever you want to call it |
| 56 | + |
| 57 | +- maybe not worth it if you really do only have that one api call |
| 58 | + |
| 59 | +but if there's more, this is great. |
| 60 | + |
| 61 | + example goes here |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +# step 2b: integration tests for the adapter |
| 67 | + |
| 68 | +* mention contract testing |
| 69 | +* you still need to solve the sandbox problem here |
| 70 | + |
| 71 | + |
| 72 | +# step 2c: unit tests for the things that use the adapter |
| 73 | + |
| 74 | +* test pyramid yay |
| 75 | + |
| 76 | + |
| 77 | +# step 2d: consider building a fake for CI |
| 78 | + |
| 79 | +* once you've got an integration working, if it's not the core |
| 80 | + of you're app, you don't your CI builds to be flakey because |
| 81 | + a third party is flakey |
| 82 | + |
| 83 | + |
| 84 | + |
| 85 | + example here |
| 86 | + |
| 87 | +pros: faster CI, faster local dev |
| 88 | +cons: need a way to occasionally run tests against the real thing. |
| 89 | + also: more code |
| 90 | + |
| 91 | + |
| 92 | +# general pros + cons re: adapters |
| 93 | + |
| 94 | +pros: |
| 95 | + * no brittle mocks everywhere |
| 96 | + * decoupling; our app code is now no longer dependeent on the specific api |
| 97 | + we're calling. if it changes, or we change it, our app doesnt need to know |
| 98 | + * and our app code looks nicer too |
| 99 | + * we've created a clear separation between things that get unit tested |
| 100 | + and things that get integration tested |
| 101 | + |
| 102 | +cons: |
| 103 | + * more code |
| 104 | + * DI is still a hard sell in the python world |
| 105 | + |
| 106 | + |
0 commit comments