Feature: Testing mocks for HTTPFetcher + FormParameter parsing - #32
Conversation
🦋 Changeset detectedLatest commit: 1890efb The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
New GermConvenienceTesting library target with: - FormParameters+Parsing: init(parsing:) extensions for Data, URLComponents, and [URLQueryItem] This helps with evaluating whether requests we send are the correct shape.
Introduces MockHTTPFetcher which conforms to HTTPFetcher allowing easier writing of test assertions: - MockHTTPFetcher: method-aware HTTP mock with per-URL handler queues, exact-to-any fallback, and request logging - HTTPResponseError: Equatable conformance to support error matching in tests
859bd8d to
a26e610
Compare
germ-mark
left a comment
There was a problem hiding this comment.
I'd suggest you adopt the three target structure of "library, mocks, tests", e.g. in
https://github.com/germ-network/AtprotoTypes
Where the mocks live in a separate target, can be adopted by downstream Mock and Test Targets. The tests can then import the library and the mock.
(I have been meaning to and this would be a good time to lift the Mockable target from AtprotoTypes to GermConvenience. don't need to do it as part of this PR, but now is a good time in this next release)
| let method: MethodMatcher | ||
| } | ||
|
|
||
| private let lock = NSLock() |
There was a problem hiding this comment.
what is the function of the lock here?
on() parked the url and method on the actor for enqueue() to read, so the pair was not atomic: two chains configuring one fetcher concurrently could enqueue a response against each other's url. Measured 24% misattribution with two tasks under load and ~97% with eight. on() now returns a Registration carrying the url and method, so the race is unrepresentable rather than unlikely, and Errors.missingOnUrl is gone with it. A drained exact-method queue with no .any handler to fall back to reported unmockedRequest, which reads as "never mocked" - the exact-to-any fallback made tooManyRequests structurally unreachable for exact keys. Registered-but-drained now reports tooManyRequests for either key. The intentional fallback to .any is unchanged. Requests that matched no handler are now logged too, matching the tooManyRequests case, so requests(for:) is a complete record of what the code under test sent. Registration urls go through the same round trip lookup uses, so on(origin) matches rather than keying a url no request can produce. Also picks up the two implicit returns from review, and corrects the changeset, which still named the target GermConvenienceTesting after the rename to GermConvenienceMocks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Make MockHTTPFetcher registration atomic and fix drained-queue reporting
The copy here would not have failed the build - it compiles with only "conformance was already stated in the type's module", and the owner's witness silently wins - so the mocks' == would have been shadowed rather than rejected. Also covers the .head rejection this branch added, which had no test, and the matching case where a bodiless method carries no body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
In order to start writing tests for oauth4swift, we needed some test helpers. This had been on my list for a while, and well, today I happened to be being annoyed by my cough so needed something to focus on.
Major changes:
.dataor.queryItems()value of FormParameters, intended for use with HTTP Testing.Minor changes, currently in GermConvenienceTesting:
As MockHTTPFetcher internally uses BundledHTTPRequest for storage, so we do actually capture the request body, so we can make an assertion about the request that we send: url, headers, body, everything.
This pull request was authored with the help of Claude, however, I largely wrote the code and claude reviewed and guided me when I got stuck with swift specifics, rather than it implementing the code (I only had it implement a few minor changes)