Swagger and OpenAPI for Testers: Read Specs and Generate Tests
On most projects the first thing you get for a new API is a link to its Swagger page. Testers who can read an OpenAPI specification properly start testing on day one, spot gaps in the contract before code is written, and generate collections, mocks and even test cases from it in minutes. This lesson teaches you to read and use OpenAPI as a tester, with a real specification for part of the SQA Tools practice API.
paths), methods, parameters, request bodies, responses, schemas, and authentication (securitySchemes). Swagger UI renders it as interactive documentation where you can “Try it out”. Testers use the spec to design test cases, find missing or ambiguous rules, import requests into Postman, generate mocks and contract tests, and detect breaking changes between versions.Swagger vs OpenAPI: Names Explained
| Term | What it is |
|---|---|
| OpenAPI Specification (OAS) | The standard itself (versions 2.0, 3.0, 3.1). 2.0 was called “Swagger 2.0”. |
| Swagger UI | Interactive HTML documentation generated from an OpenAPI file |
| Swagger Editor | Browser editor to write and validate specs |
| Swagger Codegen / OpenAPI Generator | Generate client SDKs and server stubs from the spec |
| Redoc, Stoplight, Scalar | Alternative documentation renderers |
So “send me the Swagger” usually means “send me the OpenAPI file or the Swagger UI link”. The official demo is the Petstore at petstore3.swagger.io; open it in a new tab to explore while you read.
Anatomy of an OpenAPI File
Here is an OpenAPI 3.0 description of three practice API endpoints. Read it top to bottom:
openapi: 3.0.3
info:
title: SQA Tools Practice API
version: 1.0.0
servers:
- url: https://sqatools.in/wp-json/sqa-api/v1
paths:
/users/{id}:
get:
summary: Get one user
parameters:
- name: id
in: path
required: true
schema: { type: integer, minimum: 1 }
responses:
'200':
description: The user
content:
application/json:
schema:
type: object
properties:
data: { $ref: '#/components/schemas/User' }
'400': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
/objects:
post:
summary: Create a temporary object
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/NewObject' }
responses:
'201':
description: Created
headers:
Location: { schema: { type: string, format: uri } }
ETag: { schema: { type: string } }
'413': { $ref: '#/components/responses/Error' }
'422': { $ref: '#/components/responses/Error' }
/auth/me:
get:
security: [ { bearerAuth: [] } ]
responses:
'200': { description: Current user }
'401': { $ref: '#/components/responses/Error' }
components:
securitySchemes:
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
schemas:
User:
type: object
required: [id, name, username, email, role, city, age, active, created_at]
additionalProperties: false
properties:
id: { type: integer, minimum: 1 }
name: { type: string }
username: { type: string }
email: { type: string, format: email }
role: { type: string, enum: [admin, editor, viewer] }
city: { type: string }
age: { type: integer, minimum: 18 }
active: { type: boolean }
created_at: { type: string, format: date-time }
NewObject:
type: object
required: [name]
additionalProperties: false
properties:
name: { type: string, minLength: 1, maxLength: 100 }
data: { type: object }
ttl: { type: integer, minimum: 10, maximum: 1800, default: 600 }
responses:
Error:
description: Error
content:
application/json:
schema:
type: object
properties:
error:
type: object
required: [status, code, message]
Reading it as a tester
| Section | What it tells you | Test cases it gives you |
|---|---|---|
servers | Base URLs per environment | Environment variables in Postman/Playwright |
paths + methods | Every endpoint | Coverage checklist; 405 for undeclared methods |
parameters | Path/query/header params with types, required flags, ranges | Missing, wrong type, boundaries (id 0, -1, abc) |
requestBody schema | Required fields, lengths, enums, defaults | BVA on ttl 9/10/1800/1801; name 0/1/100/101 chars; default ttl = 600 |
responses | Every documented status code and schema | One test per code; schema validation per response |
headers in responses | Location, ETag, rate limit headers | Header assertions |
security | Which endpoints need which auth | 401 without token for each secured operation |
additionalProperties: false | No extra fields allowed | Unknown field → 422; responses don’t leak fields |
Using Swagger UI to Test
- Open the Swagger UI link. Operations are grouped by tags.
- Click Authorize and paste your token or key once; it’s applied to secured calls.
- Expand an operation → Try it out → fill parameters/body → Execute.
- Swagger UI shows the cURL command, request URL, response code, body and headers.
- Compare the actual response with the documented one below it. Every mismatch is a bug in the API or in the docs.
Finding Bugs in the Spec Itself (Shift-Left)
Reviewing the spec before development is one of the highest-value things a tester can do. Questions to ask:
- Missing limits:
name: { type: string }with no maxLength. What happens with 1 MB? - Missing error responses: only
200documented. What about 400, 401, 404, 422, 429? - Ambiguous types: money as
number(float) instead of integer paise or a decimal string. - Inconsistent naming:
userIdin one place,user_idin another. - Missing pagination on list endpoints that will grow.
- Security gaps: sensitive endpoints without
security. - Enum changes: are new values allowed later without breaking mobile apps?
amount had no maximum and no relation to the original payment. The team added “amount must not exceed captured amount minus previous refunds”. The would-be bug (refunding more than was paid) never reached code.Spec vs Reality: Contract Testing
The spec is only useful if the API matches it. Compare them:
- Schema validation of every response against the spec’s schemas (Ajv in Playwright,
jsonSchemain Postman). - Undocumented endpoints: list what’s deployed and compare. The practice API exposes a discovery endpoint you can diff against docs:
https://sqatools.in/wp-json/sqa-api/v1/endpointscurl -i \
"https://sqatools.in/wp-json/sqa-api/v1/endpoints"- Undocumented status codes: the API returns 409 but the spec never mentions it.
- Breaking changes between versions: tools like
openapi-difforoasdiffcompare two spec files and flag removed endpoints, new required fields or changed types. Run them in CI on every pull request that touches the spec.
Generating Things from the Spec
| Goal | Tool | How it helps testers |
|---|---|---|
| Postman collection | Postman → Import → OpenAPI file/URL | All requests created in seconds, with example bodies |
| SoapUI/ReadyAPI project | Import Swagger/OpenAPI | Resources and methods created automatically |
| Mock server | Stoplight Prism (prism mock openapi.yaml), Postman mocks | Test front-ends and write tests before the backend exists |
| TypeScript types | openapi-typescript | Typed request/response objects in Playwright tests |
| Fuzz / property tests | Schemathesis | Thousands of generated edge-case requests; any 5xx or schema mismatch fails |
| Security scan | OWASP ZAP API scan | Automated checks on every documented endpoint |
# Mock the API locally from the spec
npx @stoplight/prism-cli mock openapi.yaml # serves on http://127.0.0.1:4010
# Fuzz the real (test) API from the spec
pip install schemathesis
schemathesis run openapi.yaml --url https://qa.example.com/api --checks all
# Detect breaking changes between two versions of the spec
oasdiff breaking old-openapi.yaml new-openapi.yaml
Using the Spec in Playwright Tests
import { test, expect } from '@playwright/test';
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
import fs from 'node:fs';
import YAML from 'yaml';
const spec = YAML.parse(fs.readFileSync('openapi.yaml', 'utf8'));
const ajv = new Ajv({ allErrors: true, strict: false });
addFormats(ajv);
const validateUser = ajv.compile(spec.components.schemas.User);
const BASE = spec.servers[0].url;
test('GET /users/{id} matches the OpenAPI User schema', async ({ request }) => {
for (const id of [1, 2, 3]) {
const res = await request.get(`${BASE}/users/${id}`);
expect(res.status()).toBe(200);
const ok = validateUser((await res.json()).data);
expect(ok, JSON.stringify(validateUser.errors)).toBe(true);
}
});
test('every documented error code for /users/{id} is reachable', async ({ request }) => {
const documented = Object.keys(spec.paths['/users/{id}'].get.responses); // ['200','400','404']
const seen = new Set([
(await request.get(`${BASE}/users/1`)).status(),
(await request.get(`${BASE}/users/abc`)).status(),
(await request.get(`${BASE}/users/999`)).status(),
].map(String));
expect([...seen].sort()).toEqual(documented.sort());
});
The tests now fail automatically when the API drifts from its contract or the contract changes without the tests.
Writing Spec-Based Test Cases: A Quick Recipe
- For each operation, list every documented response code: one test each.
- For each parameter and body field: required/optional, type, format, min/max, enum → negative and boundary tests.
- For each
securityrequirement: no token, invalid token, wrong role. - For each response schema: schema validation on positive tests.
- For each response header: assertion.
- Then add what the spec can’t express: business rules, state transitions, cross-field rules, performance.
Common Mistakes
- Trusting the spec blindly. It’s often out of date; the tests should prove it.
- Only using Swagger UI for manual clicks and never importing the spec into tools.
- Ignoring
requiredandnullabledifferences (missing vs null). - Not versioning the spec in Git alongside the code.
Interview Questions: Swagger and OpenAPI
What is the difference between Swagger and OpenAPI?
OpenAPI is the specification standard for describing REST APIs. Swagger was its original name (Swagger 2.0) and is now the name of a set of tools such as Swagger UI, Swagger Editor and Swagger Codegen that work with OpenAPI files.
How do testers use Swagger/OpenAPI?
To understand endpoints, parameters, schemas and status codes; design test cases; try requests in Swagger UI; import collections into Postman or SoapUI; validate responses against schemas; generate mocks and fuzz tests; and detect breaking changes between versions.
What are the main sections of an OpenAPI file?
openapi version, info, servers, paths (operations with parameters, requestBody and responses), components (schemas, responses, parameters, securitySchemes) and security.
What is a $ref in OpenAPI?
A reference to a reusable definition, usually under components, such as $ref: ‘#/components/schemas/User’, so schemas and responses are defined once and reused.
How do you test that an API matches its OpenAPI specification?
Validate responses against the spec’s schemas in automated tests, check every documented status code and header, compare deployed endpoints with documented ones, and run tools like Schemathesis or contract tests in CI.
What is a breaking change in an API?
A change that can break existing clients: removing an endpoint or field, renaming a field, changing a type, adding a new required request field, or narrowing allowed values. Tools like oasdiff detect them by comparing specs.
How can you start testing before the backend is ready?
Use the OpenAPI spec to write test cases and automated tests, and run them against a mock server generated from the spec (Prism or Postman mocks). When the real API is deployed, point the same tests at it.
What would you look for when reviewing an API spec?
Missing validation limits, missing error responses, ambiguous types (especially money and dates), inconsistent naming, missing pagination, missing security on sensitive endpoints, and unclear enum and nullability rules.
What is the use of the “Try it out” button in Swagger UI?
It sends real requests to the API from the documentation page and shows the request URL, cURL command, status, headers and body, which is useful for quick exploration in test environments.
Should Swagger UI be exposed in production?
It depends on whether the API is public. For internal APIs it’s often disabled or protected in production, because it exposes the full attack surface. Testers should check it matches the company’s policy.