A file upload looks like one feature and behaves like six. The browser picks the file, the network carries it, a proxy may buffer it, the server validates it, storage keeps it and something later reads it back. A bug can sit in any of those places. This guide is a test plan that covers them in order, starting with the cases that fail most often.
Before you start
Write down the rules the upload is supposed to enforce. You cannot test a limit nobody has stated. At minimum you need:
- the accepted file types
- the maximum size, and whether there is a minimum
- how many files can be sent at once
- what the user should see when a rule is broken
If those rules are not documented, finding them out is the first result of your testing.
1. The happy path
Upload the smallest valid file of each accepted type. A 1 KB text file or a 10 KB PDF is enough. Then check more than the success message:
- The file appears where the product says it will.
- Downloading it returns the same bytes. Compare SHA-256 checksums with the value on the sample's download page.
- The stored name, size and type are correct.
If the application offers both a file picker and drag-and-drop, repeat the test with each. They are separate code paths in most front ends.
2. Size limits
Test on both sides of every limit. For a 5 MB limit, upload the 1 MB file, which must succeed, and the 10 MB file, which must fail. Then try the 5 MB file itself to learn how the boundary is treated.
Two details catch people out:
- A request is bigger than the file inside it. A multipart form adds a boundary and headers, usually a few hundred bytes. A limit on the request body is therefore reached slightly before the file reaches the same number.
- There is more than one limit. A CDN, a reverse proxy, the web server, the framework and the application can each refuse a request. The lowest limit wins, and its error page may be nothing like your application's.
The guide to testing file size limits lists the defaults of common servers and frameworks.
Do not forget the lower bound. Upload the zero-byte file. An empty upload should be refused with a message, or accepted on purpose. It should never produce a server error or a record that points at nothing.
3. File types
Upload one file of a type that is not allowed and check the message. Then test whether validation looks at content or only at the name:
- Take a PNG sample and rename it so that it ends in
.pdf. - Upload it to a form that accepts PDF only.
If it is accepted, the server is trusting the file name. Do the reverse as well: a genuine PDF with a .png extension. See how to test MIME types for the full method.
Pay attention to formats that are easy to misidentify. DOCX, XLSX and PPTX files are ZIP archives and are often detected as application/zip. A file with no extension has only its content to go on.
4. File names
File names travel through URL encoding, HTTP headers, file systems and databases, and each can mangle them. Upload:
- a name with spaces
- a name with non-ASCII characters
- a very long name
- two different files with the same name, one after the other
After each upload, download the file again and look at the name the browser saves. Broken Content-Disposition headers show up here as underscores, question marks or truncated names. For the duplicate case, confirm that the second file did not silently replace the first unless that is the documented behaviour.
5. Interruptions
Use a file large enough to take several seconds, such as the 10 MB binary sample, and throttle the connection in your browser's developer tools if you need to.
- Cancel the upload midway. No partial file should be listed afterwards.
- Disconnect the network midway. The user should see an error and be able to retry.
- Close the tab midway, reopen the page and check for orphaned or half-complete records.
- Submit the form twice in quick succession. You should not end up with two copies.
6. Security checks
These are not a substitute for a security review, but they find the common mistakes quickly.
- Active content. Upload an HTML sample and an SVG sample, then open the stored file's URL directly. It should download, or be served from a separate domain, rather than render as a page on your site.
- Response headers. Stored files should be served with
X-Content-Type-Options: nosniffand aContent-Typethat matches what was validated. - Path handling. The stored location must not be derived from the user's file name. Check that a name containing
../is neutralised. - Archives. If the product unpacks ZIP files, confirm that it limits the number of entries and the total extracted size.
7. A quick command-line check
You can exercise an endpoint without a browser. This sends a file as multipart form data and prints the status code:
curl -sS -o /dev/null -w '%{http_code}\n' \
-F 'file=@sample-pdf-1mb.pdf;type=application/pdf' \
https://your-app.example/uploadSwap in larger files until the status changes from 200 or 201 to 413. That tells you where the real limit is, whatever the documentation says.
What to record
For each test, note the file name, its size in bytes and its SHA-256 checksum, the expected result and the actual result. With exact inputs written down, a developer can reproduce any failure in minutes.