Serious test-related question -- there is a bunch of code that relies on talking to an API that we do not control. How would YOU go about writing tests for code that relies on this API internally?
@grmpyprogrammer e2e test against their sandbox
@ocramius No sandbox
@grmpyprogrammer I find running tests against somebody's production API is often a good way to convince them to make a sandbox
@grmpyprogrammer mock responses where possible?
@grmpyprogrammer Hitching a ride on your question. Looking for similar advice.
@grmpyprogrammer carefully, and with the help of abstraction and fixtures.

@kboyd @grmpyprogrammer yep.

1. write abstraction wrapper layer
2. write tests (of the consumers) with mocks for that layer
3. write integration tests for that layer that call the other API.

The tests in 2 run all the time as part of your automated tests of your consuming code, the tests in 3 run periodically, maybe not even automatically, and confirm that your integration with the 3rd party still works.

(and no, that's NOT how some of our tests work, but if I had a magic wand....)

Kevin B. ⛵️ (@[email protected])

If wishes were horses, I'd be making a killing in the manure market.

PHP Community on Mastodon
@grmpyprogrammer It’s nowhere near perfect, but at a former gig we used mockserver for tests related to an external api.
@thomas I have used mockserver as well, it is not been in use at my current gig
@grmpyprogrammer assume GIGO? When you say 'internally' do you mean without network? Ditto abstraction. Interface. Facade.
@poetaster By internally I mean our code generally wraps calls to it but there are also places we call it directly
@grmpyprogrammer ah, got it. I'd put a facade on that, but it sounds like work. With an abstraction like a facade you isolate the i/o ... Otherwise you are hooped. I've recently discovered one such case in a code base I maintain. I believed everything was using the same interface. Wrong. Lucky it was only 2 calls of 12 going directly. But it cost 2 hours to track.
To expand, tests on the interface, a facade, were easy. All input, known form, template. All returns, bounds, template. Tests have discrete file templates, used in one class. Api under control.

@grmpyprogrammer Occasionally simple override when I don't care (and there are few points of injection), but mostly API adapter & test double implementing my own port (could be multiple for same library).

It often comes with a bonus of encapsulating redundant arguments. Especially when API is used in different contexts (multiple specialized adapters)

@grmpyprogrammer API itself (adapter) is tested on itegration level (with their mocks/fakes if provided).

Oh, and for libraries without side effects I usually don't bother and test them together until decomposition when test cases multiply on branching logic.

@grmpyprogrammer Depending on a few factors, I typically solve it with some kind of fake server (wiremock or basic php app), or by stubbing in the library that calls the API (intercept Guzzle calls, for example).

@afilina @grmpyprogrammer
I have an implementation where the simple built in PHP server is started (using symfony process component) before the integration tests, for my crawler package here: https://github.com/crwlrsoft/crawler/blob/main/tests/Pest.php#L24

If you can swap out the base URL for the API in your consumer, this could be a solution. Mocking could maybe be a bit easier, but I more and more like to avoid mocking as much as possible.

crawler/Pest.php at main · crwlrsoft/crawler

Library for Rapid (Web) Crawler and Scraper Development - crawler/Pest.php at main · crwlrsoft/crawler

GitHub

@grmpyprogrammer How extensive is the API interaction? Mocking could be an option unless it means completely reimplementing stone else's platform.

Is it feasible to build a fixture/testing implementation of the API that you can launch/run locally? Might be more efficient and/or less annoying than mocking frameworks.

@grmpyprogrammer I’d use my own abstraction to describe collaboration between my code and the external api. I’d stub and mock that abstraction in my tests. I’d also need to have an implementation of said abstraction and integration test it with contract tests. These would need to talk to the real thing as much as possible, depending on what third party offers. In order of preference: provided by the third party (test sandbox, stub service, fake client) , or built in house stub.
@grmpyprogrammer I normally send real requests using an HTTP client like Postman and save the JSON response to a fixture file. I then mock the request to return that data.