A measure test checks that a measure keeps returning the result you expect. The tests live in the Tests pane of the measure editor, and the Preview pane runs the measure itself so you can see its rows. The editor's lower panes are Description, Tests (<n>) and Preview; opening a pane expands the editor if it is collapsed.
A test has a kind, and each kind asks a different question of the measure:
| Kind | What it checks |
|---|---|
| Expected value | The result matches a value you enter. The value can be a Number, Text, True / false or Null; a null value means the test expects a NULL result. |
| Invariant | A rule always holds: Never negative, Never null, Between min and max, Rows sum to one, or Total equals the sum of its rows. |
| Oracle SQL | The result matches your own source-of-truth query, written over the model's BI table names. Pick the Value column to compare and, for grouped results, Key columns to match rows; they default to the group-by names. |
| Shape (runs without errors) | The measure runs without errors, over the grain you pick: Card (no group-by), Grouped rows, or Grouped rows and totals. |
Tests use one of three grains: Card (no group-by) checks a single value, Grouped rows checks one row per group, and Grouped rows and totals also checks the grand total; a Shape test must have one of them, and the grouped grains need group-by columns.
Expected value, Invariant and Oracle SQL tests can carry a Tolerance (absolute) and a Tolerance (relative). A comparison passes when the gap between the two values is within the larger of the two allowances: the absolute tolerance, or the relative tolerance applied to the expected value.
A test is created by a person or by the AI; an AI-authored test carries an AI chip on its row. For the editor around the panes, see Measure editor; for the measure library and its folders, see Measures.
500).<column> is; leave it on Any (the only row) when the query returns a single row.<name> reopens it.Save the measure to add tests. Save the measure first.Enter a test name.; an expected test without a value answers Enter the expected value. or The expected value must be a number.; a broken spec in JSON mode answers The spec must be a JSON object. or The spec is not valid JSON: <message>.<relative time> once it has one. An AI-authored test shows the AI chip. Expand a stored result to see its SQL and, for an oracle test, its Oracle SQL.Loading tests. . .; a measure with no tests shows No tests yet.<name> asks Delete test "<name>"? first. Deleting a test that changed elsewhere is quiet: the list refreshes with the newer version.<name> on its row; it runs straight away.While a run is going:
Tests of this semantic model are already running.The test runner is busy. Try again.Tests finished: N pass, N fail, N error.; it appears as a failure notice when something did not pass.The Tests pane notes Without row-level security: tests run without row-level security, so a test can check rows a viewer would not see in a report. See Row-level security and View as.
The Health tab runs all of a model's tests too; see Check, document and trace a model.
Each test shows its last stored result:
These results also feed the status dot on the measure's row in BI tables; see Measures.
more than 50 tests in scope.A test named "<name>" already exists on this measure. Choose another name or delete the other test.This measure test was changed by someone else. Reload and try again. Someone saved a change after you opened the test; reload to see their version, or overwrite it with yours.invalid measure test: shape tests need grain card, group_by or totalsinvalid measure test: expected tests need an "expected" value (null expects NULL)invalid measure test: between needs min at most maxinvalid measure test: oracle tests need sql and valueColumninvalid measure test: tolerance values must be zero or positiveinvalid measure test: a measure can have at most 50 testsThe Preview pane runs the measure itself and shows its rows.
Running the measure. . ..Row-level security hides every row from you. Unlike the preview, measure tests run without row-level security.Yes. Choose Run <name> on the test's row; it runs on its own, straight away. Use Run with dependents when the measures that use it should be checked too.
A fail means the check did not hold: a value differs, a row is missing, a key is duplicated, or a rule is violated (a Shape test fails when the measure does not run cleanly). An error means the test could not run or compare at all, for example when the query returned more rows than the test's row limit.
Yes. Turn on Against the unsaved SQL in the Tests pane and run; the tests use the expression in the editor. Such a run is not stored as the test's result, so save the measure and run again to keep one.
Only one model-wide run works per model at a time. Starting another joins the run that is already going instead of starting a second one.
No stored result exists for it yet. A new test shows Never run until its first run finishes, and saving a change to a test clears its stored result, so it returns to Never run.
The run's scope held more tests than it covers. A run with dependents covers at most 50 tests, so the rest report as not run; run them in a smaller scope.
A single run gets about one minute, and a run with dependents gets about two minutes for at most 50 tests.
Two kinds of run leave no stored result: a run against unsaved SQL, and a run whose measure or test changed while it was going. Save the measure, then run again.
No. A deleted measure hides its tests, and they come back when the measure is restored.
Creating and running tests, and reading run status, need edit access to the semantic model. If you can only view the model, you can see its tests but you cannot run them. See Who can do what in DataPrism.
If someone changed the test after you opened it, your save is refused as a version conflict. Reload to see their version, or overwrite it with yours. The refusal message is listed under When a test is refused.
Yes. The Preview pane runs the expression as it stands in the editor, saved or not. Running a preview does not save the measure.