Learn how Specmatic calculates OpenAPI API coverage by combining:
- contract tests generated from the spec, and
- routes discovered from the OpenAPI spec derived from application's controller.
Contract tests only exercise what is present in your spec. API coverage adds another question:
Is the application exposing additional routes that are implemented by the app, but missing from the spec?
That is the gap this lab demonstrates.
10-15 minutes.
- Docker is installed and running.
- You are in
labs/api-coverage-openapi. - Port
8080is available.
service/app/main.pyruns a tiny FastAPI provider on port8080.- FastAPI has a builtin mechanism to publish the app's OpenAPI document at
http://127.0.0.1:8080/openapi.json. specs/service.yamlis the published contract used by Specmatic to generate contract tests.specmatic.yamltells Specmatic where the app is running, app's published OpenAPI document and how to fetch dynamically the OpenAPI spec for API coverage enrichment.
specs/service.yaml- intentionally stale OpenAPI contract used by Specmatic.specmatic.yaml- Specmatic config withbaseUrl,swaggerUrl, and API coverage thresholds.service/app/main.py- FastAPI provider implementation.docker-compose.yaml- runs the provider and Specmatic test runner.
Fix the typo in specs/service.yaml by changing GET /pets/search to GET /pets/find.
- Do not edit
service/app/main.py. - Do not edit
specmatic.yaml. - Do not edit
docker-compose.yaml. - Edit only
specs/service.yaml.
- Contract testing overview: https://docs.specmatic.io/documentation/contract_testing.html
- Early detection of mismatches between your API specs and implementation
Specmatic first runs contract tests generated from the provided spec.
For coverage enrichment, Specmatic pulls the latest Swagger/OpenAPI from the path specified in swaggerUrl
This lab uses:
systemUnderTest.service.runOptions.openapi.baseUrlpoints contract tests tohttp://petstore:8080systemUnderTest.service.runOptions.openapi.swaggerUrlpoints coverage enrichment tohttp://petstore:8080/openapi.json
That means:
- the
specs/service.yamlcontrols which contract tests are generated - the dynamically generated OpenAPI spec at
http://petstore:8080/openapi.jsontells Specmatic which routes the application is actually exposing
This lab uses FastAPI, which can publish OpenAPI dynamically at /openapi.json. The same idea applies in other stacks as well, even though the tooling and published URL may differ.
- Spring Boot: Teams commonly use
springdoc-openapi, often together with Swagger UI, to dynamically generate and publish the OpenAPI spec from controller annotations and request mappings. - Node.js / Express: Teams commonly use packages such as
swagger-jsdocwithswagger-ui-express, or similar OpenAPI tooling, to generate and publish the spec from code annotations or configuration. - ASP.NET: Teams commonly use Swashbuckle to generate and publish OpenAPI for ASP.NET Core controllers, usually along with Swagger UI.
The important point for API coverage is not the specific library. What matters is that the application exposes a current OpenAPI document that Specmatic can fetch using swaggerUrl.
Run:
docker compose up test --build --abort-on-container-exitExpected behavior:
- The contract test for
GET /pets/{petId}passes. - The contract test for
GET /pets/searchfails because the application does not implement that route. - Specmatic fetches the app's dynamically generated OpenAPI document from
/openapi.json. - Coverage report shows
/pets/findasMissing In Spec. - Coverage report also shows
/pets/searchasNot Implemented. - The run fails because API coverage is enforced with:
minCoveragePercentage: 100maxMissedOperationsInSpec: 0
Expected result summary:
Tests run: 2, Successes: 1, Failures: 1, Errors: 0
Expected coverage highlight:
100% /pets/{petId} GET 200 1 covered
0% /pets/search GET 200 1 not implemented
0% /pets/find GET 0 0 missing in spec
Expected gate failure highlight:
Failed the following API Coverage Report success criteria:
Total API coverage: 50% is less than the specified minimum threshold of 100%.
Total missed operations: 1 is greater than the maximum threshold of 0.
Clean up:
docker compose down -vAlso inspect the generated HTML report after the run:
- Open
build/reports/specmatic/test/html/index.htmlin your browser. - Review the same mismatch in the CTRF HTML report.
- You should see
/pets/searchreported asNot Implemented. - You should also see
/pets/findreported asMissing in Spec.
Example baseline CTRF HTML report:
Open specs/service.yaml.
Find this path:
/pets/search:
get:Change it to:
/pets/find:
get:Do not change anything else in the operation.
Run the same command again:
docker compose up test --build --abort-on-container-exitExpected final result:
Tests run: 2, Successes: 2, Failures: 0, Errors: 0
Expected coverage outcome:
/pets/{petId}iscovered/pets/findiscovered- no paths remain
Missing In Spec - no paths remain
Not Implemented - API coverage success criteria pass
Clean up:
docker compose down -vAfter a run, Specmatic also generates report artifacts inside this build/reports/specmatic folder.
Important file:
build/reports/specmatic/test/html/index.html
After you fix the spec, this JSON report should include both operations:
GET /pets/{petId}GET /pets/find
The HTML report is useful both before and after the fix:
- before the fix, it shows the coverage mismatch in a more readable UI
- after the fix, it confirms both paths are covered
Start Studio and the provider:
docker compose --profile studio up --buildThen:
- Open Specmatic Studio.
- Open
specs/service.yamlfrom the left file tree. - Go to the Test tab.
- Set URL to
http://petstore:8080. - Run the tests.
In a separate browser tab, open:
What to observe before fixing the checked-in spec:
- Studio tests only the checked-in
service.yaml, so it runs the/pets/searchscenario from the given spec. - The FastAPI Swagger UI shows that the app actually publishes
GET /pets/find. - That mismatch is why the coverage report marks
/pets/findasMissing In Specand/pets/searchasNot Implemented.
Stop Studio and the provider:
docker compose --profile studio down -v- Baseline run has
1passing test and1failing test. - Coverage report shows
/pets/findasMissing In Spec. - Coverage report shows
/pets/searchasNot Implemented. - After fixing the typo in
specs/service.yaml, the rerun passes with2/2successful tests and no missed or unimplemented paths.
- If the test runner starts before the provider is ready, rerun after
docker compose down -v. - If results look stale, use
--buildexactly as documented. - If you do not see
/pets/findin Swagger UI, confirm the provider is running on127.0.0.1:8080. - If the first run does not fail as expected, confirm the checked-in spec still says
/pets/searchand not/pets/find.
- Contract tests are generated only from the checked-in spec.
- API coverage can enrich those results using routes discovered from the running application.
- With
swaggerUrl, Specmatic can dynamically fetch the app's generated OpenAPI document and identify implemented routes missing from the spec.
If you are doing this lab as part of an eLearning course, return to the eLearning site and continue with the next module.

