Testing File Upload Size Boundaries
Quick answer: A file upload limit is a byte boundary, so test it with files deliberately placed at the boundary rather than roughly sized samples: empty, one byte, limit minus one, the exact limit, and limit plus one. The exact-limit case settles whether the rule is "at or below" or strictly below, and a rejected file must never be stored. Per-file and total caps are separate checks, and a local mock can return a fixed 413 for each threshold while you confirm the client message and cleanup without moving real large files.
The limit is a byte boundary, not a rough size
A cap such as 5 MB is enforced on a precise count, so a file that looks close tells you nothing until you know its exact bytes. Generate deterministic buffers of a chosen length instead of picking documents by eye, and pin down whether the rule is less than or equal, since an off-by-one at the boundary either accepts a file the server meant to reject or blocks a valid one. Add one file far above the cap to confirm the rejection is not a fluke, and give every case a known expected result before running it.
Per-file and total request limits
| Case | Byte size | Expected | Side effect |
|---|---|---|---|
| Empty file | 0 | Accepted or clear rule | No stored content |
| Just under | limit - 1 | 200/201 | File stored |
| Exact limit | limit | Pin accept or reject | Matches the rule |
| One over | limit + 1 | 413 | Nothing stored |
| Two valid files | Each under, sum over total | 413 | Neither stored |
The last row catches a common gap: each file passes its own cap while the combined body exceeds the request-level limit. Servers often enforce both, so the suite needs a per-file threshold and a total threshold treated as distinct assertions rather than one "large upload" check.
Watch how the size is measured
The number the client displays and the number the server counts can differ. Base64 encoding grows payloads by about a third, and a multipart body adds boundary and per-part header bytes on top of the file, so the raw file size, the encoded size, and the Content-Length are not the same value. State the unit plainly, because MB can mean either a million bytes or a mebibyte, and the error message should show both the limit and the actual size. A client-side pre-check gives fast feedback, but the server stays the authority, and both should use the same exact threshold rather than rounded numbers.
Assert beyond the status code
A 413 Payload Too Large is common, though some APIs use 422, so pin the status your API returns and check Retry-After if present. Then confirm the rejected file was not stored or processed, because a status code alone does not prove the side effect was avoided. The upload should stop cleanly, the progress state reset, and the client should not resend the same oversized file in a retry loop. For the accepted boundary case, verify the file really lands and its recorded size matches. In a desktop API workspace, run the byte-sized cases as an ordered scenario against one local mock with a size-keyed response, and inspect the recorded requests. Powerduck works this way, turning each boundary into a repeatable fixed response instead of a slow manual upload.
Honest limits
A local mock proves the client handles each threshold, maps the message, and cleans up, but it does not prove the real server's byte cap. A reverse proxy or load balancer often rejects an oversized body before the application ever sees it, sometimes with its own error page, and gateway settings such as a maximum body size need a small set of genuine uploads to confirm. The mock does not store files, run malware scans, enforce disk quotas, or handle chunked and resumable uploads, and it says nothing about streaming memory use or upload timeouts on very large files. Importing a schema does not deploy a backend, and a passing mock run is not evidence about the upstream service or the network in front of it.
Frequently asked questions
Why test the exact limit instead of just one large file? The exact-limit case determines whether the rule accepts or rejects a file at the cap, which is the off-by-one a rough sample never reaches.
What is the difference between per-file and total limits? A per-file cap checks each part, while a total cap checks the whole body. Two valid files can each pass individually yet fail when combined.
Does a 413 mean the file was not saved? Not by itself. Assert against storage or a follow-up read to confirm nothing was stored, since an application can reject the request after writing part of it.
Why might the client and server disagree on size? Encoding overhead, multipart header bytes, and MB versus mebibyte rounding produce different numbers, so the test should use exact byte counts and a shared unit.
The bottom line
Treat the upload cap as an exact byte boundary and run the empty, under, exact, and over cases against both per-file and total limits, then assert storage side effects and clean failure handling rather than trusting the status code. Verify the real gateway and server caps with a few genuine uploads, since the mock only covers client behavior. For more on this approach, see the API testing guide hub.