ASP.NET Web API (.NET Framework) · Quality & Delivery

API Testing

Before automated tests, you need to poke your API and see what it really answers. Manual API testing with curl and Postman is fast, and the requests you save become living documentation.

Advanced 5 min Lesson 29 of 36Covers ASP.NET Web API 2.2 on .NET Framework 4.8.
Before you start:CRUD API
0/36 in ASP.NET Web API
On this page · 5 min · Advanced

Learning objectives#

  • Send GET, POST, PUT and DELETE requests with curl
  • Organise requests in a Postman collection with variables
  • Write simple Postman test scripts
  • Cover happy paths, errors, auth and limits for every endpoint

Explanation#

curl ships with Windows 10+, macOS and Linux. -X sets the method, -H adds headers, -d sends a body, -i shows response headers.

Postman (or Insomnia, or Visual Studio’s .http files) saves requests in collections. Environment variables such as {{baseUrl}} and {{token}} let the same collection run against local, staging and production.

Postman test scripts run after each request: pm.test("status is 201", () => pm.response.to.have.status(201)). Run the whole collection with the Collection Runner or Newman in CI.

Swagger UI’s “Try it out” is a quick way to test while reading the docs.

For every endpoint, test: the happy path, invalid input (400), missing auth (401), wrong role (403), unknown id (404), conflicts (409) and limits (page size, file size).

Syntax#

JavaScript Illustrative
// Postman → Tests tab for POST {{baseUrl}}/api/products
pm.test("returns 201", () => pm.response.to.have.status(201));
pm.test("has a Location header", () => pm.response.to.have.header("Location"));
pm.test("returns the new id", () => {
  const body = pm.response.json();
  pm.expect(body.Id).to.be.a("number");
  pm.environment.set("productId", body.Id);   // reuse in the next request
});

Code example: A curl session against the Shop API#

ShellA curl session against the Shop API Illustrative
# 1. Sign in and get a token
curl -s -X POST https://localhost:44300/token -d "grant_type=password&username=asha&password=P%40ssw0rd!"


TOKEN="paste-the-access_token-here"


# 2. Happy path: read a product (with headers shown)
curl -i https://localhost:44300/api/products/1 -H "Authorization: Bearer $TOKEN"


# 3. Create a product
curl -i -X POST https://localhost:44300/api/products -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"Name":"Bag","Price":650,"Stock":5,"Category":"Bags"}'


# 4. Invalid input
curl -i -X POST https://localhost:44300/api/products -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"Name":"","Price":-1}'


# 5. No token
curl -i https://localhost:44300/api/products/1


# 6. Delete, then delete again
curl -i -X DELETE https://localhost:44300/api/products/2 -H "Authorization: Bearer $TOKEN"
curl -i -X DELETE https://localhost:44300/api/products/2 -H "Authorization: Bearer $TOKEN"
Expected output
1 → {"access_token":"Ah3k...","token_type":"bearer","expires_in":3599}
2 → HTTP/1.1 200 OK   Content-Type: application/json; charset=utf-8   {"Id":1,"Name":"Pen",...}
3 → HTTP/1.1 201 Created   Location: https://localhost:44300/api/products/2
4 → HTTP/1.1 400 Bad Request   {"Message":"The request is invalid.","ModelState":{...}}
5 → HTTP/1.1 401 Unauthorized
6 → HTTP/1.1 204 No Content, then HTTP/1.1 404 Not Found

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. The token request uses a form-encoded body, as the OWIN /token endpoint expects (%40 is @).
  2. Storing the token in a shell variable keeps later commands short.
  3. -i prints status line and headers, so you can check Location, Content-Type and caching headers.
  4. Requests 4 and 5 deliberately break the rules to check the error responses.
  5. Deleting twice confirms DELETE is idempotent: 204, then 404.

Real-world use case#

A team keeps a Postman collection in Git next to the API. Every pull request runs it with Newman against a test deployment, so a broken status code fails the build before code review.

Common mistakes#

Testing only the happy path

Most production bugs are in error handling. Test 400, 401, 403, 404 and 409 on purpose.

Hard-coded URLs and tokens

Collections full of localhost URLs and expired tokens are useless to others. Use environment variables.

Sharing collections with real secrets

Exported environments can contain production passwords. Keep secrets in local, unshared variables.

Best practices#

  • Save every request you send in a collection
  • Use variables for base URL and token
  • Add test scripts for status and key fields
  • Run the collection in CI

Remember this#

curl -X METHOD -H "Header: value" -d body -i.

Happy path + 400 + 401 + 403 + 404 + 409.

Collections + variables + tests = reusable API checks.

Practice exercise#

Your task: Write curl commands that (1) update product 1’s name with PUT, (2) request page 2 with pageSize 5, and (3) check that pageSize=1000 is capped.

Need a hint?
Quote URLs that contain & so the shell does not split them.
Show solution
Shell Illustrative
curl -i -X PUT https://localhost:44300/api/products/1 -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"Name":"Gel Pen","Price":25,"Stock":40,"Category":"Stationery"}'


curl -s "https://localhost:44300/api/products?page=2&pageSize=5" -H "Authorization: Bearer $TOKEN"


curl -s "https://localhost:44300/api/products?page=1&pageSize=1000" -H "Authorization: Bearer $TOKEN"
# expect "PageSize":100 in the response

Mini quiz#

API Testing quizMultiple choice Question 1 of 3

Which curl option shows response headers?

Score so far: 0/0

Want more? Practise all ASP.NET Web API MCQs · ASP.NET Web API interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.