JSON
The whole run as one JSON document: the counts, and every result with its message, timing and the definition that produced it.
On this page
When to use it
For anything that reads the results by program: a pipeline step that fails the build on a failed test, a script that mails someone when a suite’s pass rate drops, a job that loads results somewhere CAT has no output for. JSON is read natively by PowerShell, Python and every CI platform. It carries everything — the complete test definition included — so nothing has to be looked up in the project file afterwards. For a human reading the file, YAML is the same data in a friendlier shape; for a test report in a pipeline, JUnit or TRX.
How to set it
Output: json
writes TestResults/cat-test-results-{timestamp}.json next to the project file. To choose the name:
Output:
- Format: json
File: results/latest.json
See Settings. Not available on the Starter and Professional plans (MS Excel only).
What it looks like
The sample run — the first result in full, the other two elided:
{
"executionGuid": "78084065-0bde-4628-b49f-f977c0f803df",
"startedOn": "2026-08-21T09:06:37.4369592+00:00",
"finishedOn": "2026-08-21T09:06:44.7333889+00:00",
"duration": "00:00:07.2964297",
"results": [
{
"executionGuid": "2ecab40f-fbcd-4d94-a2a0-28b1134f9a5c",
"testResult": "Passed",
"message": "The sets match.\n\nDescription: Every airline in the source must land in the dimension, nothing more.\nFirst Data Source: DWH\nFirst Query:\n\nSELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code\n\nSecond Data Source: DWH\nSecond Query:\n\nSELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code\n\n",
"rawMessage": "The sets match.",
"startTime": "2026-08-21T09:06:38.2510955+00:00",
"endTime": "2026-08-21T09:06:38.3266711+00:00",
"duration": "00:00:00.0755756",
"exceptionMessage": null,
"exceptions": null,
"testDefinition": {
"testDefinitionID": "aa6f2ccd-6e99-4c0e-8f4d-775c7904a628",
"suite": "Smoke tests",
"name": "Airline dimension matches the source",
"testFullName": "[Smoke tests].[Airline dimension matches the source]",
"description": "Every airline in the source must land in the dimension, nothing more.",
"firstDataSource": "DWH",
"firstQuery": "SELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code",
"secondDataSource": "DWH",
"secondQuery": "SELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code",
"expectation": "sets match",
"timeout": 0,
"maximumErrorsLogged": 1,
"tags": [],
"settings": {
"Name": "Airline dimension matches the source",
"Suite": "Smoke tests",
"Description": "Every airline in the source must land in the dimension, nothing more.",
"First data source": "DWH",
"First query": "SELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code",
"Second data source": "DWH",
"Second query": "SELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code",
"Expectation": "sets match"
}
},
"testDefinitionGuid": "aa6f2ccd-6e99-4c0e-8f4d-775c7904a628",
"testName": "Airline dimension matches the source",
"testFullName": "[Smoke tests].[Airline dimension matches the source]",
"testSuite": "Smoke tests",
"testCase": null,
"description": "Every airline in the source must land in the dimension, nothing more.",
"firstDataSource": "DWH",
"firstQuery": "SELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code",
"secondDataSource": "DWH",
"secondQuery": "SELECT 'CSA' AS Code UNION ALL SELECT 'LH' ORDER BY Code",
"expectation": "sets match",
"numberOfErrors": null,
"threadNumber": 0
},
{ "testResult": "Failed", "rawMessage": "No row was expected, but at least 1 row exists. …", "…": "…" },
{ "testResult": "Error", "exceptionMessage": "Invalid object name 'dbo.Flights'.", "…": "…" }
],
"passedCount": 1,
"failedCount": 1,
"errorCount": 1,
"inconclusiveCount": 0,
"totalCount": 3,
"passRate": 33.3,
"failedRate": 33.3,
"errorRate": 33.3,
"inconclusiveRate": 0
}
Details
One document, the run at the top. executionGuid, startedOn, finishedOn, duration, then results — one object per test — and after them the counts and rates of the whole run (passedCount, failedCount, errorCount, inconclusiveCount, totalCount, passRate, …). Keys are camelCase.
One object per result. testResult (Passed · Failed · Error · Inconclusive), message and rawMessage as described on Properties, startTime / endTime / duration, threadNumber, numberOfErrors, exceptionMessage plus exceptions — the exception chain with type and stack trace, for Error only — and testDefinition: the complete definition as CAT resolved it, including settings, the properties exactly as they were written in the source. Properties of the definition come twice: resolved (firstQuery) and as written before environment variables were expanded (firstQueryRaw). The shown sample leaves most of the definition out; the file has all of it.
Dates and durations. ISO 8601 with offset for the times (2026-08-21T09:06:38.2510955+00:00), hh:mm:ss.fffffff for durations.
The file starts with a byte-order mark (UTF-8 BOM). PowerShell’s ConvertFrom-Json and .NET readers skip it; Python’s json.load does not — open the file with encoding="utf-8-sig".
$run = Get-Content TestResults/latest.json -Raw | ConvertFrom-Json
$run.results | Where-Object testResult -ne Passed | Select-Object testFullName, testResult, rawMessage
if ($run.failedCount + $run.errorCount -gt 0) { exit 1 }
import json
with open("TestResults/latest.json", encoding="utf-8-sig") as f:
run = json.load(f)
failed = [r for r in run["results"] if r["testResult"] != "Passed"]
Written once, after the run, whatever the results; a run that is killed leaves no file. A pipeline that must fail on a failed test reads failedCount and errorCount from here — no CAT tool turns results into an exit code on its own.
Related
- YAML — the same document in YAML.
- Properties — what each field holds.
- Results — the result values.