Skip to main content

sbrs caseplans (also sbrs case-plans) is a terminal app for writing a case plan for each of your tests: a short markdown table of the steps the test performs and the result each one expects. It is the Python Case Plans Generator without the Tkinter window.

Info

What you will learn

  • How to build and launch the app.
  • Which tests it lists and where it keeps their plans.
  • How to create, edit and save a plan, and how to write the summary of all plans.

Build and launch#

Feature: tui

The app is part of the opt-in tui feature, with sbrs commander:

Note

An sbrs built without the feature still has the subcommand, but it only prints the following message and exits with status 2, as commander does.

Run it from the project root. The folder to look in is the optional argument:

A folder that has a tests or an examples folder is searched there, as commander does; any other folder is searched itself. Only the *.rs files directly inside a folder count, and they are listed by name.

sbrs caseplans --starter skips the app and writes a checklist, CASE_PLANS.md, in the current folder. It never replaces a file that is there, and it works in every build.

What is listed#

Every test function, one row each: tests/login.rs::valid_login is the test valid_login of tests/login.rs. A function counts when a test attribute (#[test], #[tokio::test], #[rstest]) comes before it. This is a read of the text, not a parse, so a #[test] inside a string looks like a test. A file with no test function is listed as the file alone.

Each row shows [x] when you have marked it and [plan] when its plan exists.

Where plans go#

The plan of a test is case_plans/<name>.md in the folder of its file, where the name is the last part of the row with :: turned into .:

tests
login.rsholds the test valid_login
about.rsa file with no test function, listed as the file alone
case_plansplans of the files directly in tests/
login.valid_login.mdthe plan of tests/login.rs::valid_login
about.rs.mdthe plan of tests/about.rs
ui
cart.rsholds the test empty
case_plansplans of the files in tests/ui/
cart.empty.mdthe plan of tests/ui/cart.rs::empty
Info

Cargo ignores a case_plans folder inside tests/, so the plans do not become test targets.

A new plan is the Python template:

New plan template

Keys#

On the list:

KeyAction
↓ / ↑ or j / kMove (wraps around at either end)
PageDown / PageUp, Home / EndMove a page, or to the first or last row
SpaceMark or unmark the row
a / nMark every row shown / clear all marks
cCreate a boilerplate plan for each marked test that has none (for the row under the cursor when nothing is marked). A plan that exists is never replaced.
Enter or eOpen the plan of the row in the editor
sWrite the summary to case_summary.md
/ or fFilter the rows (case-insensitive); Enter keeps the filter, Esc clears it
rList the tests again; marks are kept
q or Ctrl-CQuit

In the editor:

KeyAction
Characters, Enter, Backspace, DeleteEdit
Arrow keys, Home, End, PageUp, PageDownMove the cursor
Ctrl-SSave the plan
EscBack to the list
Ctrl-CQuit

When the plan has changes that are not saved, Esc and Ctrl-C ask first: s saves and then closes (or quits), d throws the changes away, and Esc goes on editing. A plan is saved with LF line ends and a closing newline.

The summary#

s writes case_summary.md in the current folder, for the listed tests that have a plan, and says how many of each kind there are:

  • a plan whose table was filled in,
  • a plan that is still the template,
  • a plan with no table yet.

The file counts them in a table and folds each plan into a <details> block, as the Python summary does, so it reads well on a code host. It is replaced each time.

Differences from Python#

  • It runs in the terminal; Python opens a Tkinter window.
  • Python lists the tests pytest collects (test_file.py::Class::test_method); this lists Rust test functions found in the files.
  • Python only creates boilerplate plans. Here you can also open a plan, edit it and save it without leaving the app.
  • Python writes plans and the summary with CRLF line ends; this writes LF.