Kater CLI Build and check test
kater test
Runs the tests of your shared models, and says which ones pass and which ones fail.
A test is a fixed question with a fixed answer: these fields, over these dates, return exactly these rows. Run the tests after you change a model, or after new data loads, so that no number moves by surprise. It runs on the warehouse unless you add --local or --compile-only. Its subcommands write draft tests, list the tests and check a model’s readiness. kater new test adds one test. See Tests.
Commands
| Command | What it does |
|---|---|
kater test update | Mark a draft test as checked. |
kater test list | List tests and how each one last ran. |
kater test snapshot | Copy the rows your tests read to this machine. |
kater test readiness | Say whether a model is ready to hand off. |
kater test generate | Write a starting set of draft tests for a model. |
Examples
# Run every test of the connection that you can readkater test --select connection:snowflake_prod_connection# Run the tests of the shared ad_reporting modelkater test --select semantic.ad_reporting# Run the tests that have the tag team=marketingkater test --select tag:team=marketing# Run one test, and print the SQL that each of its paths rankater test --select july_2026_totals_by_platform --show-sql# Run the merge check: only the tests that a change since main could movekater test --select state:modified+ --state git:main --stale# Keep the new rows of the failing tests, after a change that you meant to makekater test --select semantic.ad_reporting --update# Write five draft tests for the shared ad_reporting modelkater test generate --model semantic.ad_reporting# List the model's tests and how each one last rankater test list --model semantic.ad_reporting# Check whether the model is ready to hand offkater test readiness --model semantic.ad_reportingOptions
It also takes the global options --json, --kater-root, --scope and --help.
Where tests live
Each model’s tests are in one file, named after the model. A test file can be in one of three places in the connection’s folder:
| Where | Whose tests |
|---|---|
modeling/kater_objects/tests/<model>.sql | The shared layer’s tests. Everyone who reads the model reads them. Only these count toward readiness. |
users/<email>/tests/<model>.sql | Your own tests. A new test goes here unless you add --shared. |
workspaces/<workspace>/tests/<root>.sql | The tests of a connection workspace’s root, with its parameters and filters. |
What a test holds
- A question. It asks its question as field picker selections, as hand-written Kater SQL, or both. Kater checks each one.
- An expected answer. It expects exact
rows, the same answer as another query (same_as), or the code that the compiler refuses the SQL with (refused). - Optional keys.
as_ofsets the day that the test takes as today, for relative dates.givengives a fixture’s rows in place of the warehouse’s.inputsgives a connection workspace’s root its parameter values and filters.
Which tests run
With no --select, it runs every test of the connection that you are in, or of your only connection, that you can read. That is the shared layer’s tests, each connection workspace’s tests, your own, and any that someone shared with you. A run reads the tests of one connection only. When a selection reaches tests of more than one connection, the run stops: add connection:NAME to the selection, such as --select connection:snowflake_prod_connection,tag:team=marketing.
kater test and kater test snapshot take the connection from --select. The other test commands take --connection. Without them, Kater uses the folder of the Files terminal. Or else it uses the one connection whose shared models include --model, or your only connection.
What it prints
Each test prints a line when it starts and a line when it ends, as kater build shows them. Tests that run on the warehouse run side by side, so their lines can end in a different order. The run ends with its time, a block for each test that failed, and a summary. It writes target/run_results.json.
PASSandFAIL. The test returned the expected answer, or it did not.FAIL 4counts the values that differ.ERROR. The test could not run, or it is not written correctly.WARN. The test has no answer yet, such as asame_astest with no native SQL. With--compile-onlyor--stale, a test whose SQL moved since its last pass also warns.PASSwith--compile-onlyor--stale. The test’s SQL did not move since its last pass, so it did not run.
With --show-sql or --update, a list follows the summary: each test with the SQL that it ran, or each number that --update recorded again. With --json, the answer is the run’s own JSON, with each test in items.
Columns compare by position. Numbers compare at the decimal places that their format shows, such as cents. When a test fails and its SQL did not change since its last pass, the message says that the data changed. A draft with no answer yet keeps the rows of its first run that returns rows.
The merge check
--select state:modified+ --state git:main --stale runs only the tests that a change since main could reach: the tests of each file that this branch changed, and of each model that reads those files. Of those, it runs only the tests whose compiled SQL moved since their last pass. --state git:main reads git in your local copy: the files committed since this branch left main, changed but not committed, or new. The other tests count as unchanged.
Results and exit codes
- Where results go. In your own terminal, each warehouse run is recorded in
.kater/test-status/in your content root. A local run is recorded apart, and it never makes a test pass or stale.kater test listandkater test readinessread these records. - Exit codes.
0when no test failed,1when a test failed or could not run, and2for a command that is not valid. A draft with no answer yet does not fail the run. With--compile-only, a stale test does not fail the run.